diff options
75 files changed, 539 insertions, 818 deletions
diff --git a/server/sonar-docs/src/tooltips/branches/no-branch-support.md b/server/sonar-docs/src/tooltips/branches/no-branch-support.md new file mode 100644 index 00000000000..82854211584 --- /dev/null +++ b/server/sonar-docs/src/tooltips/branches/no-branch-support.md @@ -0,0 +1,7 @@ +**Get the most out of SonarQube with branches analysis** + +Analyze each branch of your project separately with the Developer Edition. + +--- + +[Learn More](https://redirect.sonarsource.com/editions/developer.html) diff --git a/server/sonar-docs/src/tooltips/branches/single-branch.md b/server/sonar-docs/src/tooltips/branches/single-branch.md new file mode 100644 index 00000000000..c4184a27de5 --- /dev/null +++ b/server/sonar-docs/src/tooltips/branches/single-branch.md @@ -0,0 +1,7 @@ +**Learn how to analyze branches in SonarQube** + +Quickly setup branch analysis and get separate insights for each of your branches and pull requests. + +--- + +[Branches Documentation](/branches/index) diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java index 9dbb657f824..2184ce4a581 100644 --- a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java +++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/QualityProfilePage.java @@ -30,13 +30,13 @@ public class QualityProfilePage { public QualityProfilePage shouldHaveMissingSonarWayRules(Integer nbRules) { Selenide.$(".quality-profile-rules-sonarway-missing") .shouldBe(Condition.visible) - .$("a").shouldHave(Condition.text(nbRules.toString())); + .shouldHave(Condition.text(nbRules.toString())); return this; } public RulesPage showMissingSonarWayRules() { Selenide.$(".quality-profile-rules-sonarway-missing") - .shouldBe(Condition.visible).$("a").click(); + .shouldBe(Condition.visible).$("[data-test=\"rules\"]").click(); return Selenide.page(RulesPage.class); } diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx index ac864c7dea1..637a95e3fca 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx @@ -21,11 +21,13 @@ import * as React from 'react'; import * as PropTypes from 'prop-types'; import { Link } from 'react-router'; import { SuggestionLink } from './SuggestionsProvider'; +import { CurrentUser, isLoggedIn } from '../../types'; import BubblePopup, { BubblePopupPosition } from '../../../components/common/BubblePopup'; import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/urls'; interface Props { + currentUser: CurrentUser; onClose: () => void; popupPosition?: BubblePopupPosition; suggestions: Array<SuggestionLink>; @@ -93,6 +95,7 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> { translate('embed_docs.contact_form') )} </li> + <li className="divider" /> {this.renderTitle(translate('embed_docs.stay_connected'))} <li> {this.renderIconLink('https://about.sonarcloud.io/news/', 'sc-icon.svg', 'Product News')} @@ -107,11 +110,13 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> { renderSonarQubeLinks() { return ( <React.Fragment> - <li> - <a href="#" onClick={this.onAnalyzeProjectClick}> - {translate('embed_docs.analyze_new_project')} - </a> - </li> + {isLoggedIn(this.props.currentUser) && ( + <li> + <a href="#" onClick={this.onAnalyzeProjectClick}> + {translate('embed_docs.analyze_new_project')} + </a> + </li> + )} <li className="divider" /> {this.renderTitle(translate('embed_docs.get_support'))} <li> @@ -128,6 +133,7 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> { 'Stack Overflow' )} </li> + <li className="divider" /> {this.renderTitle(translate('embed_docs.stay_connected'))} <li> {this.renderIconLink('https://blog.sonarsource.com/', 'sq-icon.svg', 'Product News')} @@ -148,7 +154,7 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> { {this.renderSuggestions()} <li> <Link onClick={this.props.onClose} to="/documentation"> - {translate('embed_docs.documentation_index')} + {translate('embed_docs.documentation')} </Link> </li> <li> diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx index aca948c6aa9..29b58e4e6e3 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx @@ -20,12 +20,14 @@ import * as React from 'react'; import EmbedDocsPopup from './EmbedDocsPopup'; import { SuggestionLink } from './SuggestionsProvider'; +import { CurrentUser } from '../../types'; import BubblePopupHelper from '../../../components/common/BubblePopupHelper'; import HelpIcon from '../../../components/icons-components/HelpIcon'; import Tooltip from '../../../components/controls/Tooltip'; import { translate } from '../../../helpers/l10n'; interface Props { + currentUser: CurrentUser; showTooltip: boolean; suggestions: Array<SuggestionLink>; tooltip: boolean; @@ -79,7 +81,13 @@ export default class EmbedDocsPopupHelper extends React.PureComponent<Props, Sta <BubblePopupHelper isOpen={this.state.helpOpen} offset={{ horizontal: 12, vertical: -10 }} - popup={<EmbedDocsPopup onClose={this.closeHelp} suggestions={this.props.suggestions} />} + popup={ + <EmbedDocsPopup + currentUser={this.props.currentUser} + onClose={this.closeHelp} + suggestions={this.props.suggestions} + /> + } position="bottomleft" togglePopup={this.setHelpDisplay}> <Tooltip diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx index 647715c847a..48bb8a0799a 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx @@ -25,9 +25,16 @@ const suggestions = [{ link: '#', text: 'foo' }, { link: '#', text: 'bar' }]; it('should display suggestion links', () => { const context = {}; - const wrapper = shallow(<EmbedDocsPopups onClose={jest.fn()} suggestions={suggestions} />, { - context - }); + const wrapper = shallow( + <EmbedDocsPopups + currentUser={{ isLoggedIn: true }} + onClose={jest.fn()} + suggestions={suggestions} + />, + { + context + } + ); wrapper.update(); expect(wrapper).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap index 8867991dcc5..b1af003796f 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap @@ -48,7 +48,7 @@ exports[`should display suggestion links 1`] = ` style={Object {}} to="/documentation" > - embed_docs.documentation_index + embed_docs.documentation </Link> </li> <li> @@ -111,6 +111,9 @@ exports[`should display suggestion links 1`] = ` </a> </li> <li + className="divider" + /> + <li className="dropdown-header" > embed_docs.stay_connected diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx index 5569d2a7844..890e4d5f29e 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx @@ -22,8 +22,7 @@ import * as classNames from 'classnames'; import * as PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; import ComponentNavBranchesMenu from './ComponentNavBranchesMenu'; -import SingleBranchHelperPopup from './SingleBranchHelperPopup'; -import NoBranchSupportPopup from './NoBranchSupportPopup'; +import DocTooltip from '../../../../components/docs/DocTooltip'; import { BranchLike, Component } from '../../../types'; import * as theme from '../../../theme'; import BranchIcon from '../../../../components/icons-components/BranchIcon'; @@ -35,7 +34,7 @@ import { } from '../../../../helpers/branches'; import { translate } from '../../../../helpers/l10n'; import PlusCircleIcon from '../../../../components/icons-components/PlusCircleIcon'; -import Popup from '../../../../components/controls/Popup'; +import HelpTooltip from '../../../../components/controls/HelpTooltip'; import Tooltip from '../../../../components/controls/Tooltip'; interface Props { @@ -110,10 +109,11 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State if (isShortLivingBranch(currentBranchLike)) { return currentBranchLike.isOrphan ? ( <span className="note big-spacer-left text-ellipsis flex-shrink"> - {translate('branches.orphan_branch')} - <Tooltip overlay={translate('branches.orphan_branches.tooltip')}> - <i className="icon-help spacer-left" /> - </Tooltip> + <span className="text-middle">{translate('branches.orphan_branch')}</span> + <HelpTooltip + className="spacer-left" + overlay={translate('branches.orphan_branches.tooltip')} + /> </span> ) : ( <span className="note big-spacer-left"> @@ -138,26 +138,6 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State } }; - renderSingleBranchPopup = () => ( - <Popup overlay={<SingleBranchHelperPopup />}> - {({ onClick }) => ( - <a className="display-flex-center spacer-left link-no-underline" href="#" onClick={onClick}> - <PlusCircleIcon fill={theme.blue} size={12} /> - </a> - )} - </Popup> - ); - - renderNoBranchSupportPopup = () => ( - <Popup overlay={<NoBranchSupportPopup />}> - {({ onClick }) => ( - <a className="display-flex-center spacer-left link-no-underline" href="#" onClick={onClick}> - <PlusCircleIcon fill={theme.gray80} size={12} /> - </a> - )} - </Popup> - ); - render() { const { branchLikes, currentBranchLike } = this.props; @@ -176,7 +156,9 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State fill={theme.gray80} /> <span className="note">{displayName}</span> - {this.renderNoBranchSupportPopup()} + <DocTooltip className="spacer-left" doc="branches/no-branch-support"> + <PlusCircleIcon fill={theme.gray71} size={12} /> + </DocTooltip> </div> ); } @@ -186,7 +168,9 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State <div className="navbar-context-branches"> <BranchIcon branchLike={currentBranchLike} className="little-spacer-right" /> <span className="note">{displayName}</span> - {this.renderSingleBranchPopup()} + <DocTooltip className="spacer-left" doc="branches/single-branch"> + <PlusCircleIcon fill={theme.blue} size={12} /> + </DocTooltip> </div> ); } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenu.tsx index 4f2849bdfd8..10f4b1ba885 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenu.tsx @@ -34,7 +34,7 @@ import { import { translate } from '../../../../helpers/l10n'; import { getBranchLikeUrl } from '../../../../helpers/urls'; import SearchBox from '../../../../components/controls/SearchBox'; -import Tooltip from '../../../../components/controls/Tooltip'; +import HelpTooltip from '../../../../components/controls/HelpTooltip'; interface Props { branchLikes: BranchLike[]; @@ -196,10 +196,13 @@ export default class ComponentNavBranchesMenu extends React.PureComponent<Props, {showDivider && <li className="divider" />} {showOrphanHeader && ( <li className="dropdown-header"> - {translate('branches.orphan_branches')} - <Tooltip overlay={translate('branches.orphan_branches.tooltip')}> - <i className="icon-help spacer-left" /> - </Tooltip> + <div className="display-inline-block text-middle"> + {translate('branches.orphan_branches')} + </div> + <HelpTooltip + className="spacer-left" + overlay={translate('branches.orphan_branches.tooltip')} + /> </li> )} {showPullRequestHeader && ( diff --git a/server/sonar-web/src/main/js/app/components/nav/component/SingleBranchHelperPopup.tsx b/server/sonar-web/src/main/js/app/components/nav/component/SingleBranchHelperPopup.tsx deleted file mode 100644 index b569b999505..00000000000 --- a/server/sonar-web/src/main/js/app/components/nav/component/SingleBranchHelperPopup.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { translate } from '../../../../helpers/l10n'; - -export default function SingleBranchHelperPopup() { - return ( - <> - <h6 className="spacer-bottom">{translate('branches.learn_how_to_analyze')}</h6> - <p className="big-spacer-bottom markdown"> - {translate('branches.learn_how_to_analyze.text')} - </p> - <a - className="button" - href="https://redirect.sonarsource.com/doc/branches.html" - rel="noopener noreferrer" - target="_blank"> - {translate('about_page.read_documentation')} - </a> - </> - ); -} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx index 2c2651988af..8ea67da8b97 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx @@ -114,7 +114,7 @@ it('renders single branch popup', () => { />, { context: { branchesEnabled: true } } ); - expect(wrapper.find('Popup')).toMatchSnapshot(); + expect(wrapper.find('DocTooltip')).toMatchSnapshot(); }); it('renders no branch support popup', () => { @@ -127,7 +127,7 @@ it('renders no branch support popup', () => { />, { context: { branchesEnabled: false } } ); - expect(wrapper.find('Popup')).toMatchSnapshot(); + expect(wrapper.find('DocTooltip')).toMatchSnapshot(); }); it('renders nothing on SonarCloud without branch support', () => { diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranch-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranch-test.tsx.snap index c3042574729..dc23c7b4368 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranch-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranch-test.tsx.snap @@ -36,9 +36,15 @@ exports[`renders main branch 1`] = ` `; exports[`renders no branch support popup 1`] = ` -<Popup - overlay={<NoBranchSupportPopup />} -/> +<DocTooltip + className="spacer-left" + doc="branches/no-branch-support" +> + <PlusCircleIcon + fill="#b4b4b4" + size={12} + /> +</DocTooltip> `; exports[`renders pull request 1`] = ` @@ -150,7 +156,13 @@ exports[`renders short-living branch 1`] = ` `; exports[`renders single branch popup 1`] = ` -<Popup - overlay={<SingleBranchHelperPopup />} -/> +<DocTooltip + className="spacer-left" + doc="branches/single-branch" +> + <PlusCircleIcon + fill="#4b9fd5" + size={12} + /> +</DocTooltip> `; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenu-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenu-test.tsx.snap index a8c10d0f990..c104c23e7d3 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenu-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenu-test.tsx.snap @@ -80,14 +80,15 @@ exports[`renders list 1`] = ` <li className="dropdown-header" > - branches.orphan_branches - <Tooltip - overlay="branches.orphan_branches.tooltip" + <div + className="display-inline-block text-middle" > - <i - className="icon-help spacer-left" - /> - </Tooltip> + branches.orphan_branches + </div> + <HelpTooltip + className="spacer-left" + overlay="branches.orphan_branches.tooltip" + /> </li> <ComponentNavBranchesMenuItem branchLike={ @@ -177,14 +178,15 @@ exports[`renders list 1`] = ` <li className="dropdown-header" > - branches.orphan_branches - <Tooltip - overlay="branches.orphan_branches.tooltip" + <div + className="display-inline-block text-middle" > - <i - className="icon-help spacer-left" - /> - </Tooltip> + branches.orphan_branches + </div> + <HelpTooltip + className="spacer-left" + overlay="branches.orphan_branches.tooltip" + /> </li> <ComponentNavBranchesMenuItem branchLike={ diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/NoBranchSupportPopup-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/NoBranchSupportPopup-test.tsx.snap deleted file mode 100644 index 964fc40a823..00000000000 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/NoBranchSupportPopup-test.tsx.snap +++ /dev/null @@ -1,25 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<React.Fragment> - <h6 - className="spacer-bottom" - > - branches.no_support.header - </h6> - <p - className="big-spacer-bottom markdown" - > - branches.no_support.header.text - </p> - <p> - <a - href="https://redirect.sonarsource.com/editions/developer.html" - rel="noopener noreferrer" - target="_blank" - > - learn_more - </a> - </p> -</React.Fragment> -`; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/SingleBranchHelperPopup-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/SingleBranchHelperPopup-test.tsx.snap deleted file mode 100644 index a27c56302eb..00000000000 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/SingleBranchHelperPopup-test.tsx.snap +++ /dev/null @@ -1,24 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<React.Fragment> - <h6 - className="spacer-bottom" - > - branches.learn_how_to_analyze - </h6> - <p - className="big-spacer-bottom markdown" - > - branches.learn_how_to_analyze.text - </p> - <a - className="button" - href="https://redirect.sonarsource.com/doc/branches.html" - rel="noopener noreferrer" - target="_blank" - > - about_page.read_documentation - </a> -</React.Fragment> -`; diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx index b91c43abb47..866edfae805 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx @@ -101,6 +101,7 @@ class GlobalNav extends React.PureComponent<Props, State> { <GlobalNavExplore location={this.props.location} onSonarCloud={this.props.onSonarCloud} /> <li> <EmbedDocsPopupHelper + currentUser={this.props.currentUser} showTooltip={this.state.onboardingTutorialTooltip} suggestions={this.props.suggestions} tooltip={!this.props.onSonarCloud} diff --git a/server/sonar-web/src/main/js/app/styles/init/icons.css b/server/sonar-web/src/main/js/app/styles/init/icons.css index 55a8586e8ea..c4f46239db3 100644 --- a/server/sonar-web/src/main/js/app/styles/init/icons.css +++ b/server/sonar-web/src/main/js/app/styles/init/icons.css @@ -430,12 +430,6 @@ a:hover > .icon-radio { } } -.icon-help:before { - content: '\f059'; - color: var(--blue); - font-size: var(--bigFontSize); -} - .icon-close:before { content: '\f00d'; font-size: var(--bigFontSize); diff --git a/server/sonar-web/src/main/js/app/utils/exposeLibraries.ts b/server/sonar-web/src/main/js/app/utils/exposeLibraries.ts index 798f70d69d2..b07d8c1f53b 100644 --- a/server/sonar-web/src/main/js/app/utils/exposeLibraries.ts +++ b/server/sonar-web/src/main/js/app/utils/exposeLibraries.ts @@ -32,6 +32,7 @@ import LicenseEditionSet from '../../apps/marketplace/components/LicenseEditionS import HomePageSelect from '../../components/controls/HomePageSelect'; import ListFooter from '../../components/controls/ListFooter'; import Modal from '../../components/controls/Modal'; +import HelpTooltip from '../../components/controls/HelpTooltip'; import SearchBox from '../../components/controls/SearchBox'; import Select from '../../components/controls/Select'; import Tooltip from '../../components/controls/Tooltip'; @@ -60,6 +61,7 @@ const exposeLibraries = () => { DuplicationsRating, EditButton, FavoriteContainer, + HelpTooltip, HomePageSelect, Level, LicenseEditionSet, diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/NoWorkersSupportPopup.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/NoWorkersSupportPopup.tsx index c6e327896fc..b1f851e0d36 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/NoWorkersSupportPopup.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/NoWorkersSupportPopup.tsx @@ -18,27 +18,25 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import BubblePopup from '../../../components/common/BubblePopup'; import { translate } from '../../../helpers/l10n'; -interface Props { - popupPosition?: any; -} - -export default function NoWorkersSupportPopup(props: Props) { +export default function NoWorkersSupportPopup() { return ( - <BubblePopup position={props.popupPosition} customClass="bubble-popup-bottom-right"> - <div className="abs-width-400"> - <h6 className="spacer-bottom">{translate('background_tasks.add_more_workers')}</h6> - <p className="big-spacer-bottom markdown"> - {translate('background_tasks.add_more_workers.text')} - </p> - <p> - <a href="https://redirect.sonarsource.com/editions/enterprise.html" target="_blank"> - {translate('learn_more')} - </a> - </p> - </div> - </BubblePopup> + <> + <p className="spacer-bottom"> + <strong>{translate('background_tasks.add_more_workers')}</strong> + </p> + <p className="big-spacer-bottom markdown"> + {translate('background_tasks.add_more_workers.text')} + </p> + <p> + <a + href="https://redirect.sonarsource.com/editions/enterprise.html" + rel="noopener noreferrer" + target="_blank"> + {translate('learn_more')} + </a> + </p> + </> ); } diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Workers.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/Workers.tsx index 1039418df33..5f448358cfa 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/Workers.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Workers.tsx @@ -21,10 +21,8 @@ import * as React from 'react'; import WorkersForm from './WorkersForm'; import NoWorkersSupportPopup from './NoWorkersSupportPopup'; import AlertWarnIcon from '../../../components/icons-components/AlertWarnIcon'; -import BubblePopupHelper from '../../../components/common/BubblePopupHelper'; -import HelpIcon from '../../../components/icons-components/HelpIcon'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import Tooltip from '../../../components/controls/Tooltip'; -import * as theme from '../../../app/theme'; import { getWorkers } from '../../../api/ce'; import { translate } from '../../../helpers/l10n'; import { EditButton } from '../../../components/ui/buttons'; @@ -103,15 +101,12 @@ export default class Workers extends React.PureComponent<{}, State> { const { canSetWorkerCount, formOpen, loading, workerCount } = this.state; return ( - <div> + <div className="display-flex-center"> {!loading && workerCount > 1 && ( <Tooltip overlay={translate('background_tasks.number_of_workers.warning')}> - <span> - <AlertWarnIcon - className="little-spacer-right bt-workers-warning-icon" - fill="#d3d3d3" - /> + <span className="display-inline-flex-center little-spacer-right"> + <AlertWarnIcon fill="#d3d3d3" /> </span> </Tooltip> )} @@ -138,17 +133,7 @@ export default class Workers extends React.PureComponent<{}, State> { {!loading && !canSetWorkerCount && ( - <span className="spacer-left"> - <a className="link-no-underline" href="#" onClick={this.handleHelpClick}> - <HelpIcon className="text-text-bottom" fill={theme.gray80} /> - </a> - <BubblePopupHelper - isOpen={this.state.noSupportPopup} - popup={<NoWorkersSupportPopup />} - position="bottomright" - togglePopup={this.toggleNoSupportPopup} - /> - </span> + <HelpTooltip className="spacer-left" overlay={<NoWorkersSupportPopup />} /> )} {formOpen && <WorkersForm onClose={this.closeForm} workerCount={this.state.workerCount} />} diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.tsx.snap b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.tsx.snap index 48dea3cb94d..a579c086680 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/__tests__/__snapshots__/Workers-test.tsx.snap @@ -1,7 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`opens form 1`] = ` -<div> +<div + className="display-flex-center" +> <span className="text-middle" > @@ -24,7 +26,9 @@ exports[`opens form 1`] = ` `; exports[`opens form 2`] = ` -<div> +<div + className="display-flex-center" +> <span className="text-middle" > @@ -51,7 +55,9 @@ exports[`opens form 2`] = ` `; exports[`renders 1`] = ` -<div> +<div + className="display-flex-center" +> <span className="text-middle" > @@ -64,7 +70,9 @@ exports[`renders 1`] = ` `; exports[`renders 2`] = ` -<div> +<div + className="display-flex-center" +> <span className="text-middle" > @@ -87,13 +95,16 @@ exports[`renders 2`] = ` `; exports[`renders 3`] = ` -<div> +<div + className="display-flex-center" +> <Tooltip overlay="background_tasks.number_of_workers.warning" > - <span> + <span + className="display-inline-flex-center little-spacer-right" + > <AlertWarnIcon - className="little-spacer-right bt-workers-warning-icon" fill="#d3d3d3" /> </span> @@ -120,13 +131,16 @@ exports[`renders 3`] = ` `; exports[`renders 4`] = ` -<div> +<div + className="display-flex-center" +> <Tooltip overlay="background_tasks.number_of_workers.warning" > - <span> + <span + className="display-inline-flex-center little-spacer-right" + > <AlertWarnIcon - className="little-spacer-right bt-workers-warning-icon" fill="#d3d3d3" /> </span> @@ -141,31 +155,17 @@ exports[`renders 4`] = ` 2 </strong> </span> - <span + <HelpTooltip className="spacer-left" - > - <a - className="link-no-underline" - href="#" - onClick={[Function]} - > - <HelpIcon - className="text-text-bottom" - fill="#cdcdcd" - /> - </a> - <BubblePopupHelper - isOpen={false} - popup={<NoWorkersSupportPopup />} - position="bottomright" - togglePopup={[Function]} - /> - </span> + overlay={<NoWorkersSupportPopup />} + /> </div> `; exports[`updates worker count 1`] = ` -<div> +<div + className="display-flex-center" +> <span className="text-middle" > @@ -192,13 +192,16 @@ exports[`updates worker count 1`] = ` `; exports[`updates worker count 2`] = ` -<div> +<div + className="display-flex-center" +> <Tooltip overlay="background_tasks.number_of_workers.warning" > - <span> + <span + className="display-inline-flex-center little-spacer-right" + > <AlertWarnIcon - className="little-spacer-right bt-workers-warning-icon" fill="#d3d3d3" /> </span> diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js b/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js index dad5a4ec0e2..9031eacd7af 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js +++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChart.js @@ -22,8 +22,7 @@ import React from 'react'; import EmptyResult from './EmptyResult'; import OriginalBubbleChart from '../../../components/charts/BubbleChart'; import ColorRatingsLegend from '../../../components/charts/ColorRatingsLegend'; -import Tooltip from '../../../components/controls/Tooltip'; -import HelpIcon from '../../../components/icons-components/HelpIcon'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import { formatMeasure, isDiffMetric } from '../../../helpers/measures'; import { getLocalizedMetricDomain, @@ -170,12 +169,8 @@ export default class BubbleChart extends React.PureComponent { return ( <div className="measure-overview-bubble-chart-header"> <span className="measure-overview-bubble-chart-title"> - {title} - <Tooltip overlay={this.getDescription(domain)}> - <span className="spacer-left text-info"> - <HelpIcon /> - </span> - </Tooltip> + <span className="text-middle">{title}</span> + <HelpTooltip className="spacer-left" overlay={this.getDescription(domain)} /> </span> <span className="measure-overview-bubble-chart-legend"> <span className="note"> diff --git a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx index 90b0bfb46ea..c623b78944d 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx @@ -27,6 +27,7 @@ import ScreenPositionHelper from '../../../components/common/ScreenPositionHelpe import DocMarkdownBlock from '../../../components/docs/DocMarkdownBlock'; import DeferredSpinner from '../../../components/common/DeferredSpinner'; import { translate } from '../../../helpers/l10n'; +import '../styles.css'; interface Props { params: { splat?: string }; @@ -87,7 +88,7 @@ export default class App extends React.PureComponent<Props, State> { return ( <div className="boxed-group"> <DocMarkdownBlock - className="cut-margins boxed-group-inner" + className="documentation-content cut-margins boxed-group-inner" content={this.state.content} displayH1={true} /> @@ -122,7 +123,9 @@ export default class App extends React.PureComponent<Props, State> { </ScreenPositionHelper> <div className="layout-page-main"> - <div className="layout-page-main-inner">{this.renderContent()}</div> + <div className="layout-page-main-inner documentation-layout-inner"> + {this.renderContent()} + </div> </div> </div> ); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/NoBranchSupportPopup-test.tsx b/server/sonar-web/src/main/js/apps/documentation/styles.css index 14c49cc4c5a..089f3e36189 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/NoBranchSupportPopup-test.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/styles.css @@ -17,10 +17,11 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import NoBranchSupportPopup from '../NoBranchSupportPopup'; +.documentation-layout-inner { + max-width: 740px; +} -it('renders', () => { - expect(shallow(<NoBranchSupportPopup />)).toMatchSnapshot(); -}); +.documentation-content > h1 { + margin-bottom: calc(4 * var(--gridSize)); + font-size: 20px; +} diff --git a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx index a58ead1f8c7..3bec8113a96 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx @@ -28,7 +28,7 @@ import SearchSelect from '../../../components/controls/SearchSelect'; import Checkbox from '../../../components/controls/Checkbox'; import Modal from '../../../components/controls/Modal'; import Select from '../../../components/controls/Select'; -import Tooltip from '../../../components/controls/Tooltip'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import SeverityHelper from '../../../components/shared/SeverityHelper'; import Avatar from '../../../components/ui/Avatar'; import { SubmitButton } from '../../../components/ui/buttons'; @@ -457,10 +457,11 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> { return ( <div className="modal-field"> <label htmlFor="comment"> - {translate('issue.comment.formlink')} - <Tooltip overlay={translate('issue_bulk_change.comment.help')}> - <i className="icon-help little-spacer-left" /> - </Tooltip> + <span className="text-middle">{translate('issue.comment.formlink')}</span> + <HelpTooltip + className="spacer-left" + overlay={translate('issue_bulk_change.comment.help')} + /> </label> <div> <textarea diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGate.js b/server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGate.js index 8c647e71b56..5c575d3cd23 100644 --- a/server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGate.js +++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/QualityGate.js @@ -21,12 +21,10 @@ import React from 'react'; import QualityGateConditions from './QualityGateConditions'; import EmptyQualityGate from './EmptyQualityGate'; -import * as theme from '../../../app/theme'; import { translate } from '../../../helpers/l10n'; import Level from '../../../components/ui/Level'; -import Tooltip from '../../../components/controls/Tooltip'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import DocTooltip from '../../../components/docs/DocTooltip'; -import HelpIcon from '../../../components/icons-components/HelpIcon'; /*:: import type { Component, MeasuresList } from '../types'; */ function parseQualityGateDetails(rawDetails /*: string */) { @@ -73,12 +71,13 @@ export default function QualityGate({ branchLike, component, measures } /*: Prop {ignoredConditions && ( <div className="alert alert-info display-inline-block big-spacer-top"> - {translate('overview.quality_gate.ignored_conditions')} - <Tooltip overlay={translate('overview.quality_gate.ignored_conditions.tooltip')}> - <span className="spacer-left"> - <HelpIcon fill={theme.blue} /> - </span> - </Tooltip> + <span className="text-middle"> + {translate('overview.quality_gate.ignored_conditions')} + </span> + <HelpTooltip + className="spacer-left" + overlay={translate('overview.quality_gate.ignored_conditions.tooltip')} + /> </div> )} diff --git a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGate-test.js.snap b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGate-test.js.snap index 2387806ada6..2e09cfa0f8c 100644 --- a/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGate-test.js.snap +++ b/server/sonar-web/src/main/js/apps/overview/qualityGate/__tests__/__snapshots__/QualityGate-test.js.snap @@ -25,18 +25,15 @@ exports[`renders message about ignored conditions 1`] = ` <div className="alert alert-info display-inline-block big-spacer-top" > - overview.quality_gate.ignored_conditions - <Tooltip - overlay="overview.quality_gate.ignored_conditions.tooltip" + <span + className="text-middle" > - <span - className="spacer-left" - > - <HelpIcon - fill="#4b9fd5" - /> - </span> - </Tooltip> + overview.quality_gate.ignored_conditions + </span> + <HelpTooltip + className="spacer-left" + overlay="overview.quality_gate.ignored_conditions.tooltip" + /> </div> </div> `; diff --git a/server/sonar-web/src/main/js/apps/permission-templates/components/ListHeader.js b/server/sonar-web/src/main/js/apps/permission-templates/components/ListHeader.js index 897521276c5..4be5290b446 100644 --- a/server/sonar-web/src/main/js/apps/permission-templates/components/ListHeader.js +++ b/server/sonar-web/src/main/js/apps/permission-templates/components/ListHeader.js @@ -19,7 +19,7 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import Tooltip from '../../../components/controls/Tooltip'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import { translate } from '../../../helpers/l10n'; export default class ListHeader extends React.PureComponent { @@ -42,11 +42,9 @@ export default class ListHeader extends React.PureComponent { render() { const cells = this.props.permissions.map(permission => ( - <th key={permission.key} className="permission-column"> - {translate('projects_role', permission.key)} - <Tooltip overlay={this.renderTooltip(permission)}> - <i className="icon-help little-spacer-left" /> - </Tooltip> + <th className="permission-column" key={permission.key}> + <span className="text-middle">{translate('projects_role', permission.key)}</span> + <HelpTooltip className="spacer-left" overlay={this.renderTooltip(permission)} /> </th> )); diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/PermissionHeader.tsx b/server/sonar-web/src/main/js/apps/permissions/shared/components/PermissionHeader.tsx index f00777de1bb..07d1787fded 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/components/PermissionHeader.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/shared/components/PermissionHeader.tsx @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import HelpTooltip from '../../../../components/controls/HelpTooltip'; import Tooltip from '../../../../components/controls/Tooltip'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; @@ -69,13 +70,11 @@ export default class PermissionHeader extends React.PureComponent<Props> { 'global_permissions.filter_by_x_permission', permission.name )}> - <a href="#" onClick={this.handlePermissionClick}> + <a className="text-middle" href="#" onClick={this.handlePermissionClick}> {permission.name} </a> </Tooltip> - <Tooltip overlay={this.renderTooltip(permission)}> - <i className="icon-help little-spacer-left" /> - </Tooltip> + <HelpTooltip className="spacer-left" overlay={this.renderTooltip(permission)} /> </div> </th> ); diff --git a/server/sonar-web/src/main/js/apps/permissions/styles.css b/server/sonar-web/src/main/js/apps/permissions/styles.css index 6707fe36d9f..eae759f0acb 100644 --- a/server/sonar-web/src/main/js/apps/permissions/styles.css +++ b/server/sonar-web/src/main/js/apps/permissions/styles.css @@ -29,5 +29,5 @@ } .permissions-table .permission-column-inner { - width: 112px; + width: 100px; } diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx index 949bc4e1d78..6298f16e0a3 100644 --- a/server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/projectBranches/components/App.tsx @@ -32,7 +32,7 @@ import { import { translate } from '../../../helpers/l10n'; import { getValues } from '../../../api/settings'; import { formatMeasure } from '../../../helpers/measures'; -import Tooltip from '../../../components/controls/Tooltip'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; interface Props { branchLikes: BranchLike[]; @@ -154,10 +154,13 @@ export default class App extends React.PureComponent<Props, State> { <React.Fragment key={getBranchLikeKey(branchLike)}> {showOrphanHeader && ( <li className="dropdown-header"> - {translate('branches.orphan_branches')} - <Tooltip overlay={translate('branches.orphan_branches.tooltip')}> - <i className="icon-help spacer-left" /> - </Tooltip> + <div className="display-inline-block text-middle"> + {translate('branches.orphan_branches')} + </div> + <HelpTooltip + className="spacer-left" + overlay={translate('branches.orphan_branches.tooltip')} + /> </li> )} <BranchRow diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap index d2e776bbee4..5c8f4b20cf0 100644 --- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/App-test.tsx.snap @@ -150,14 +150,15 @@ exports[`renders sorted list of branches 1`] = ` <li className="dropdown-header" > - branches.orphan_branches - <Tooltip - overlay="branches.orphan_branches.tooltip" + <div + className="display-inline-block text-middle" > - <i - className="icon-help spacer-left" - /> - </Tooltip> + branches.orphan_branches + </div> + <HelpTooltip + className="spacer-left" + overlay="branches.orphan_branches.tooltip" + /> </li> <BranchRow branchLike={ diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx index a82b86d69fd..56609711677 100644 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx +++ b/server/sonar-web/src/main/js/apps/projects/visualizations/Risk.tsx @@ -25,8 +25,7 @@ import { formatMeasure } from '../../../helpers/measures'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { RATING_COLORS } from '../../../helpers/constants'; import { getProjectUrl } from '../../../helpers/urls'; -import Tooltip from '../../../components/controls/Tooltip'; -import HelpIcon from '../../../components/icons-components/HelpIcon'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; const X_METRIC = 'sqale_index'; const X_METRIC_TYPE = 'SHORT_WORK_DUR'; @@ -138,12 +137,8 @@ export default class Risk extends React.PureComponent<Props> { </div> <div className="measure-details-bubble-chart-axis size"> <span className="measure-details-bubble-chart-title"> - {translate('projects.visualization.risk')} - <Tooltip overlay={this.props.helpText}> - <span className="spacer-left text-info"> - <HelpIcon /> - </span> - </Tooltip> + <span className="text-middle">{translate('projects.visualization.risk')}</span> + <HelpTooltip className="spacer-left" overlay={this.props.helpText} /> </span> <div> <span className="spacer-right"> diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx b/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx index 10c1291f61f..be1e6ee0f8c 100644 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx +++ b/server/sonar-web/src/main/js/apps/projects/visualizations/SimpleBubbleChart.tsx @@ -25,8 +25,7 @@ import { translate, translateWithParameters } from '../../../helpers/l10n'; import { RATING_COLORS } from '../../../helpers/constants'; import { getProjectUrl } from '../../../helpers/urls'; import { Project } from '../types'; -import Tooltip from '../../../components/controls/Tooltip'; -import HelpIcon from '../../../components/icons-components/HelpIcon'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; export interface Metric { key: string; @@ -129,12 +128,8 @@ export default class SimpleBubbleChart extends React.PureComponent<Props> { </div> <div className="measure-details-bubble-chart-axis size"> <span className="measure-details-bubble-chart-title"> - {this.props.title} - <Tooltip overlay={this.props.helpText}> - <span className="spacer-left text-info"> - <HelpIcon className="text-bottom" /> - </span> - </Tooltip> + <span className="text-middle">{this.props.title}</span> + <HelpTooltip className="spacer-left" overlay={this.props.helpText} /> </span> <div> {colorMetric != null && ( diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap index ec17ac106b4..c1aac43c7d7 100644 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/Risk-test.tsx.snap @@ -100,16 +100,15 @@ exports[`renders 1`] = ` <span className="measure-details-bubble-chart-title" > - projects.visualization.risk - <Tooltip - overlay="foobar" + <span + className="text-middle" > - <span - className="spacer-left text-info" - > - <HelpIcon /> - </span> - </Tooltip> + projects.visualization.risk + </span> + <HelpTooltip + className="spacer-left" + overlay="foobar" + /> </span> <div> <span diff --git a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap index 020df683ca2..0c07a84920e 100644 --- a/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/visualizations/__tests__/__snapshots__/SimpleBubbleChart-test.tsx.snap @@ -89,17 +89,13 @@ exports[`renders 1`] = ` <span className="measure-details-bubble-chart-title" > - <Tooltip + <span + className="text-middle" + /> + <HelpTooltip + className="spacer-left" overlay="foobar" - > - <span - className="spacer-left text-info" - > - <HelpIcon - className="text-bottom" - /> - </span> - </Tooltip> + /> </span> <div> <span diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx index 54d3e0704d8..7c82c9e6d22 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx @@ -26,7 +26,7 @@ import { Organization } from '../../app/types'; import Checkbox from '../../components/controls/Checkbox'; import { translate } from '../../helpers/l10n'; import QualifierIcon from '../../components/shared/QualifierIcon'; -import Tooltip from '../../components/controls/Tooltip'; +import HelpTooltip from '../../components/controls/HelpTooltip'; import DateInput from '../../components/controls/DateInput'; import Select from '../../components/controls/Select'; import SearchBox from '../../components/controls/SearchBox'; @@ -156,13 +156,14 @@ export default class Search extends React.PureComponent<Props, State> { className="link-checkbox-control" id="projects-provisioned" onCheck={this.props.onProvisionedChanged}> - <span className="little-spacer-left"> + <span className="text-middle little-spacer-left"> {translate('provisioning.only_provisioned')} - <Tooltip overlay={translate('provisioning.only_provisioned.tooltip')}> - <i className="spacer-left icon-help" /> - </Tooltip> </span> </Checkbox> + <HelpTooltip + className="spacer-left" + overlay={translate('provisioning.only_provisioned.tooltip')} + /> </td> ) : null; diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap index 66cec9365f8..544cef96516 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectsManagement/__tests__/__snapshots__/Search-test.tsx.snap @@ -101,18 +101,15 @@ exports[`render qualifiers filter 1`] = ` thirdState={false} > <span - className="little-spacer-left" + className="text-middle little-spacer-left" > provisioning.only_provisioned - <Tooltip - overlay="provisioning.only_provisioned.tooltip" - > - <i - className="spacer-left icon-help" - /> - </Tooltip> </span> </Checkbox> + <HelpTooltip + className="spacer-left" + overlay="provisioning.only_provisioned.tooltip" + /> </td> <td className="text-middle" @@ -188,18 +185,15 @@ exports[`renders 1`] = ` thirdState={false} > <span - className="little-spacer-left" + className="text-middle little-spacer-left" > provisioning.only_provisioned - <Tooltip - overlay="provisioning.only_provisioned.tooltip" - > - <i - className="spacer-left icon-help" - /> - </Tooltip> </span> </Checkbox> + <HelpTooltip + className="spacer-left" + overlay="provisioning.only_provisioned.tooltip" + /> </td> <td className="text-middle" diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx index 88f976df8fb..4ebd702fa00 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/BuiltInQualityGateBadge.tsx @@ -20,14 +20,14 @@ import * as React from 'react'; import * as classNames from 'classnames'; import Tooltip from '../../../components/controls/Tooltip'; +import DocInclude from '../../../components/docs/DocInclude'; import { translate } from '../../../helpers/l10n'; interface Props { className?: string; - tooltip?: boolean; } -export default function BuiltInQualityGateBadge({ className, tooltip = true }: Props) { +export default function BuiltInQualityGateBadge({ className }: Props) { const badge = ( <div className={classNames('outline-badge', className)}> {translate('quality_gates.built_in')} @@ -35,13 +35,11 @@ export default function BuiltInQualityGateBadge({ className, tooltip = true }: P ); const overlay = ( - <div> - <span>{translate('quality_gates.built_in.description.1')}</span> - <span className="little-spacer-left"> - {translate('quality_gates.built_in.description.2')} - </span> - </div> + <DocInclude + className="abs-width-300 cut-margins" + path="/tooltips/quality-gates/built-in-quality-gate" + /> ); - return <Tooltip overlay={tooltip ? overlay : undefined}>{badge}</Tooltip>; + return <Tooltip overlay={overlay}>{badge}</Tooltip>; } diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx index 8e2b1aa14ba..c4c869924a3 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx @@ -23,7 +23,6 @@ import RenameQualityGateForm from './RenameQualityGateForm'; import CopyQualityGateForm from './CopyQualityGateForm'; import DeleteQualityGateForm from './DeleteQualityGateForm'; import { fetchQualityGate, QualityGate, setQualityGateAsDefault } from '../../../api/quality-gates'; -import DocTooltip from '../../../components/docs/DocTooltip'; import { Button } from '../../../components/ui/buttons'; import { translate } from '../../../helpers/l10n'; @@ -76,12 +75,7 @@ export default class DetailsHeader extends React.PureComponent<Props, State> { <div className="layout-page-main-inner"> <div className="pull-left display-flex-center"> <h2>{qualityGate.name}</h2> - {qualityGate.isBuiltIn && ( - <> - <BuiltInQualityGateBadge className="spacer-left" /> - <DocTooltip className="spacer-left" doc="quality-gates/built-in-quality-gate" /> - </> - )} + {qualityGate.isBuiltIn && <BuiltInQualityGateBadge className="spacer-left" />} </div> <div className="pull-right"> diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/List.js b/server/sonar-web/src/main/js/apps/quality-gates/components/List.js index 69db7ff0a73..a1319df5af5 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/List.js +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/List.js @@ -40,7 +40,7 @@ export default function List({ organization, qualityGates }) { <td className="thin nowrap spacer-left text-right"> {qualityGate.isDefault && <span className="badge">{translate('default')}</span>} {qualityGate.isBuiltIn && ( - <BuiltInQualityGateBadge className="little-spacer-left" tooltip={false} /> + <BuiltInQualityGateBadge className="little-spacer-left" /> )} </td> </tr> diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/BuiltInQualityProfileBadge.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/BuiltInQualityProfileBadge.tsx index f493d0dc2c8..16b64e80812 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/components/BuiltInQualityProfileBadge.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/BuiltInQualityProfileBadge.tsx @@ -20,6 +20,7 @@ import * as React from 'react'; import * as classNames from 'classnames'; import Tooltip from '../../../components/controls/Tooltip'; +import DocInclude from '../../../components/docs/DocInclude'; import { translate } from '../../../helpers/l10n'; interface Props { @@ -35,10 +36,10 @@ export default function BuiltInQualityProfileBadge({ className, tooltip = true } ); const overlay = ( - <span> - {translate('quality_profiles.built_in.description.1')}{' '} - {translate('quality_profiles.built_in.description.2')} - </span> + <DocInclude + className="abs-width-300 cut-margins" + path="/tooltips/quality-profiles/built-in-quality-profile" + /> ); return <Tooltip overlay={tooltip ? overlay : undefined}>{badge}</Tooltip>; diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.tsx index 7a5dfe71a4c..3940f9c61e3 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import ProfileLink from '../components/ProfileLink'; import BuiltInQualityProfileBadge from '../components/BuiltInQualityProfileBadge'; -import Tooltip from '../../../components/controls/Tooltip'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import { translate, translateWithParameters } from '../../../helpers/l10n'; interface Props { @@ -50,19 +50,21 @@ export default function ProfileInheritanceBox({ displayLink = true, ...props }: <div style={{ paddingLeft: offset }}> {displayLink ? ( <ProfileLink + className="text-middle" language={props.language} name={profile.name} organization={props.organization}> {profile.name} </ProfileLink> ) : ( - profile.name + <span className="text-middle">{profile.name}</span> )} {profile.isBuiltIn && <BuiltInQualityProfileBadge className="spacer-left" />} {extendsBuiltIn && ( - <Tooltip overlay={translate('quality_profiles.extends_built_in')}> - <i className="icon-help spacer-left" /> - </Tooltip> + <HelpTooltip + className="spacer-left" + overlay={translate('quality_profiles.extends_built_in')} + /> )} </div> </td> diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesDeprecatedWarning.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesDeprecatedWarning.tsx index e2cd08698ce..1422fddb049 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesDeprecatedWarning.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesDeprecatedWarning.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import { Link } from 'react-router'; -import Tooltip from '../../../components/controls/Tooltip'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import { getDeprecatedActiveRulesUrl } from '../../../helpers/urls'; import { translate } from '../../../helpers/l10n'; @@ -33,10 +33,11 @@ export default function ProfileRulesDeprecatedWarning(props: Props) { return ( <div className="quality-profile-rules-deprecated clearfix"> <span className="pull-left"> - {translate('quality_profiles.deprecated_rules')} - <Tooltip overlay={translate('quality_profiles.deprecated_rules_description')}> - <i className="icon-help spacer-left" /> - </Tooltip> + <span className="text-middle">{translate('quality_profiles.deprecated_rules')}</span> + <HelpTooltip + className="spacer-left" + overlay={translate('quality_profiles.deprecated_rules_description')} + /> </span> <Link className="pull-right" diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx index 2a14b31b4ba..3a305bca091 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import { Link } from 'react-router'; -import Tooltip from '../../../components/controls/Tooltip'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import { getRulesUrl } from '../../../helpers/urls'; import { translate } from '../../../helpers/l10n'; @@ -45,12 +45,13 @@ export default function ProfileRulesSonarWayComparison(props: Props) { return ( <div className="quality-profile-rules-sonarway-missing clearfix"> <span className="pull-left"> - {translate('quality_profiles.sonarway_missing_rules')} - <Tooltip overlay={translate('quality_profiles.sonarway_missing_rules_description')}> - <i className="icon-help spacer-left" /> - </Tooltip> + <span className="text-middle">{translate('quality_profiles.sonarway_missing_rules')}</span> + <HelpTooltip + className="spacer-left" + overlay={translate('quality_profiles.sonarway_missing_rules_description')} + /> </span> - <Link className="pull-right" to={url}> + <Link className="pull-right" data-test="rules" to={url}> {props.sonarWayMissingRules} </Link> </div> diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap index ace1b6fe12a..308c513f84f 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap @@ -7,14 +7,15 @@ exports[`should render correctly 1`] = ` <span className="pull-left" > - quality_profiles.deprecated_rules - <Tooltip - overlay="quality_profiles.deprecated_rules_description" + <span + className="text-middle" > - <i - className="icon-help spacer-left" - /> - </Tooltip> + quality_profiles.deprecated_rules + </span> + <HelpTooltip + className="spacer-left" + overlay="quality_profiles.deprecated_rules_description" + /> </span> <Link className="pull-right" diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap index 4719fd50cf5..69d5092c589 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap @@ -7,17 +7,19 @@ exports[`should render correctly 1`] = ` <span className="pull-left" > - quality_profiles.sonarway_missing_rules - <Tooltip - overlay="quality_profiles.sonarway_missing_rules_description" + <span + className="text-middle" > - <i - className="icon-help spacer-left" - /> - </Tooltip> + quality_profiles.sonarway_missing_rules + </span> + <HelpTooltip + className="spacer-left" + overlay="quality_profiles.sonarway_missing_rules_description" + /> </span> <Link className="pull-right" + data-test="rules" onlyActiveOnIndex={false} style={Object {}} to={ diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx index a0b3302ff48..d05b77b2fda 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.tsx @@ -28,7 +28,7 @@ import { getRulesUrl } from '../../../helpers/urls'; import { isStagnant } from '../utils'; import { Profile } from '../types'; import Tooltip from '../../../components/controls/Tooltip'; -import DocTooltip from '../../../components/docs/DocTooltip'; +import DocInclude from '../../../components/docs/DocInclude'; interface Props { onRequestFail: (reason: any) => void; @@ -51,12 +51,7 @@ export default class ProfilesListRow extends React.PureComponent<Props> { {profile.name} </ProfileLink> </div> - {profile.isBuiltIn && ( - <> - <BuiltInQualityProfileBadge className="spacer-left" /> - <DocTooltip className="spacer-left" doc="quality-profiles/built-in-quality-profile" /> - </> - )} + {profile.isBuiltIn && <BuiltInQualityProfileBadge className="spacer-left" />} </div> ); } @@ -66,10 +61,15 @@ export default class ProfilesListRow extends React.PureComponent<Props> { if (profile.isDefault) { return ( - <> + <Tooltip + overlay={ + <DocInclude + className="abs-width-300 cut-margins" + path="/tooltips/quality-profiles/default-quality-profile" + /> + }> <span className="badge">{translate('default')}</span> - <DocTooltip className="table-cell-doc" doc="quality-profiles/default-quality-profile" /> - </> + </Tooltip> ); } diff --git a/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css b/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css index f77c7c0220b..696beeb9cdc 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css +++ b/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.css @@ -63,8 +63,8 @@ .oauth-providers-help { position: absolute; - top: 12px; - right: -32px; + top: 15px; + right: -24px; } .oauth-providers + .login-form { diff --git a/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx b/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx index b13fae5dd5e..1ecf27de26e 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx @@ -20,10 +20,8 @@ import * as React from 'react'; import * as classNames from 'classnames'; import { translateWithParameters } from '../../../helpers/l10n'; -import * as theme from '../../../app/theme'; import { IdentityProvider } from '../../../app/types'; -import Tooltip from '../../../components/controls/Tooltip'; -import HelpIcon from '../../../components/icons-components/HelpIcon'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import { isDarkColor } from '../../../helpers/colors'; import { getBaseUrl } from '../../../helpers/urls'; import './OAuthProviders.css'; @@ -80,11 +78,7 @@ function OAuthProvider({ format, identityProvider, returnTo }: ItemProps) { <span>{format(identityProvider.name)}</span> </a> {identityProvider.helpMessage && ( - <Tooltip overlay={identityProvider.helpMessage}> - <div className="oauth-providers-help"> - <HelpIcon fill={theme.blue} /> - </div> - </Tooltip> + <HelpTooltip className="oauth-providers-help" overlay={identityProvider.helpMessage} /> )} </li> ); diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap index e37305eb820..7ab0639e474 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/OAuthProviders-test.tsx.snap @@ -81,17 +81,10 @@ exports[`should render correctly 3`] = ` login.login_with_x.Bar </span> </a> - <Tooltip + <HelpTooltip + className="oauth-providers-help" overlay="Help message!" - > - <div - className="oauth-providers-help" - > - <HelpIcon - fill="#4b9fd5" - /> - </div> - </Tooltip> + /> </li> `; diff --git a/server/sonar-web/src/main/js/apps/web-api/components/Search.tsx b/server/sonar-web/src/main/js/apps/web-api/components/Search.tsx index 1f098d804c9..49bc4e20220 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/Search.tsx +++ b/server/sonar-web/src/main/js/apps/web-api/components/Search.tsx @@ -19,8 +19,7 @@ */ import * as React from 'react'; import Checkbox from '../../../components/controls/Checkbox'; -import HelpIcon from '../../../components/icons-components/HelpIcon'; -import Tooltip from '../../../components/controls/Tooltip'; +import HelpTooltip from '../../../components/controls/HelpTooltip'; import { translate } from '../../../helpers/l10n'; import SearchBox from '../../../components/controls/SearchBox'; @@ -42,27 +41,25 @@ export default function Search(props: Props) { </div> <div className="big-spacer-top"> - <Checkbox checked={showInternal} onCheck={onToggleInternal}> + <Checkbox checked={showInternal} className="text-middle" onCheck={onToggleInternal}> <span className="little-spacer-left">{translate('api_documentation.show_internal')}</span> </Checkbox> - <Tooltip overlay={translate('api_documentation.internal_tooltip')}> - <span> - <HelpIcon className="spacer-left text-info" /> - </span> - </Tooltip> + <HelpTooltip + className="spacer-left" + overlay={translate('api_documentation.internal_tooltip')} + /> </div> <div className="spacer-top"> - <Checkbox checked={showDeprecated} onCheck={onToggleDeprecated}> + <Checkbox checked={showDeprecated} className="text-middle" onCheck={onToggleDeprecated}> <span className="little-spacer-left"> {translate('api_documentation.show_deprecated')} </span> </Checkbox> - <Tooltip overlay={translate('api_documentation.deprecation_tooltip')}> - <span> - <HelpIcon className="spacer-left text-info" /> - </span> - </Tooltip> + <HelpTooltip + className="spacer-left" + overlay={translate('api_documentation.deprecation_tooltip')} + /> </div> </div> ); diff --git a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap index 339160fb83b..1802e140988 100644 --- a/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/web-api/components/__tests__/__snapshots__/Search-test.tsx.snap @@ -15,6 +15,7 @@ exports[`should render correctly 1`] = ` > <Checkbox checked={false} + className="text-middle" onCheck={[Function]} thirdState={false} > @@ -24,21 +25,17 @@ exports[`should render correctly 1`] = ` api_documentation.show_internal </span> </Checkbox> - <Tooltip + <HelpTooltip + className="spacer-left" overlay="api_documentation.internal_tooltip" - > - <span> - <HelpIcon - className="spacer-left text-info" - /> - </span> - </Tooltip> + /> </div> <div className="spacer-top" > <Checkbox checked={false} + className="text-middle" onCheck={[Function]} thirdState={false} > @@ -48,15 +45,10 @@ exports[`should render correctly 1`] = ` api_documentation.show_deprecated </span> </Checkbox> - <Tooltip + <HelpTooltip + className="spacer-left" overlay="api_documentation.deprecation_tooltip" - > - <span> - <HelpIcon - className="spacer-left text-info" - /> - </span> - </Tooltip> + /> </div> </div> `; diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx index 2a23425df06..c2898e6725f 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx @@ -19,6 +19,7 @@ */ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; +import { Link } from 'react-router'; import { translate } from '../../../helpers/l10n'; interface Props { @@ -40,12 +41,7 @@ export default function PageHeader({ children, loading }: Props) { id={'webhooks.description'} values={{ url: ( - <a - href="https://redirect.sonarsource.com/doc/webhooks.html" - rel="noopener noreferrer" - target="_blank"> - {translate('webhooks.documentation_link')} - </a> + <Link to="/documentation/webhooks">{translate('webhooks.documentation_link')}</Link> ) }} /> diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap index e44b8019fca..ce4b526d41d 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/PageHeader-test.tsx.snap @@ -21,13 +21,13 @@ exports[`should render correctly 1`] = ` id="webhooks.description" values={ Object { - "url": <a - href="https://redirect.sonarsource.com/doc/webhooks.html" - rel="noopener noreferrer" - target="_blank" + "url": <Link + onlyActiveOnIndex={false} + style={Object {}} + to="/documentation/webhooks" > webhooks.documentation_link - </a>, + </Link>, } } /> diff --git a/server/sonar-web/src/main/js/components/common/BranchStatus.tsx b/server/sonar-web/src/main/js/components/common/BranchStatus.tsx index b54a82c8fb1..1738e5c1fa1 100644 --- a/server/sonar-web/src/main/js/components/common/BranchStatus.tsx +++ b/server/sonar-web/src/main/js/components/common/BranchStatus.tsx @@ -22,7 +22,7 @@ import StatusIndicator from './StatusIndicator'; import Level from '../ui/Level'; import BugIcon from '../icons-components/BugIcon'; import CodeSmellIcon from '../icons-components/CodeSmellIcon'; -import HelpIcon from '../icons-components/HelpIcon'; +import HelpTooltip from '../controls/HelpTooltip'; import Tooltip from '../controls/Tooltip'; import VulnerabilityIcon from '../icons-components/VulnerabilityIcon'; import { BranchLike } from '../../app/types'; @@ -81,15 +81,14 @@ export default function BranchStatus({ branchLike, concise = false }: Props) { <CodeSmellIcon className="little-spacer-left" /> </li> {shouldDisplayHelper && ( - <Tooltip + <HelpTooltip + className="spacer-left" overlay={translateWithParameters( 'branches.short_lived.quality_gate.description', totalIssues - )}> - <li className="spacer-left"> - <HelpIcon className="text-info" /> - </li> - </Tooltip> + )} + tagName="li" + /> )} </ul> ); diff --git a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap index 369c4f0b9d2..bf868d3263c 100644 --- a/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/BranchStatus-test.tsx.snap @@ -167,16 +167,10 @@ exports[`renders status of short-living branches 4`] = ` className="little-spacer-left" /> </li> - <Tooltip + <HelpTooltip + className="spacer-left" overlay="branches.short_lived.quality_gate.description.1" - > - <li - className="spacer-left" - > - <HelpIcon - className="text-info" - /> - </li> - </Tooltip> + tagName="li" + /> </ul> `; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/SingleBranchHelperPopup-test.tsx b/server/sonar-web/src/main/js/components/controls/HelpTooltip.css index a6185bce650..09c45fb1f38 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/SingleBranchHelperPopup-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/HelpTooltip.css @@ -17,10 +17,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import SingleBranchHelperPopup from '../SingleBranchHelperPopup'; +.help-tooltip { + display: inline-flex; + align-items: center; + vertical-align: middle; +} -it('renders', () => { - expect(shallow(<SingleBranchHelperPopup />)).toMatchSnapshot(); -}); +.help-toolip-link { + display: block; + width: 12px; + height: 12px; + border: none; +} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/NoBranchSupportPopup.tsx b/server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx index 5493c37d39c..bc68b868f4d 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/NoBranchSupportPopup.tsx +++ b/server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx @@ -18,21 +18,28 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { translate } from '../../../../helpers/l10n'; +import * as classNames from 'classnames'; +import Tooltip from './Tooltip'; +import HelpIcon from '../icons-components/HelpIcon'; +import * as theme from '../../app/theme'; +import './HelpTooltip.css'; -export default function NoBranchSupportPopup() { - return ( - <> - <h6 className="spacer-bottom">{translate('branches.no_support.header')}</h6> - <p className="big-spacer-bottom markdown">{translate('branches.no_support.header.text')}</p> - <p> - <a - href="https://redirect.sonarsource.com/editions/developer.html" - rel="noopener noreferrer" - target="_blank"> - {translate('learn_more')} - </a> - </p> - </> +interface Props { + className?: string; + children?: React.ReactNode; + onShow?: () => void; + overlay: React.ReactNode; + tagName?: string; +} + +export default function HelpTooltip(props: Props) { + const { children = <HelpIcon fill={theme.gray71} size={12} />, tagName = 'div' } = props; + + return React.createElement( + tagName, + { className: classNames('help-tooltip', props.className) }, + <Tooltip mouseLeaveDelay={0.25} onShow={props.onShow} overlay={props.overlay}> + <span className="display-inline-flex-center">{children}</span> + </Tooltip> ); } diff --git a/server/sonar-web/src/main/js/components/controls/Popup.tsx b/server/sonar-web/src/main/js/components/controls/Popup.tsx deleted file mode 100644 index 68f8415f4e5..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Popup.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import OutsideClickHandler from './OutsideClickHandler'; -import Tooltip from './Tooltip'; - -interface Props { - children: (props: { onClick: () => void }) => React.ReactElement<any>; - overlay: React.ReactNode; -} - -interface State { - visible: boolean; -} - -export default class Popup extends React.Component<Props, State> { - state: State = { visible: false }; - - componentWillReceiveProps(nextProps: Props) { - if (nextProps.overlay !== this.props.overlay) { - this.setState({ visible: false }); - } - } - - handleClick = (event?: React.MouseEvent<HTMLElement>) => { - if (event) { - event.preventDefault(); - event.currentTarget.blur(); - } - - // defer opening to not trigger OutsideClickHandler.onClickOutside callback - setTimeout(() => { - this.setState({ visible: true }); - }, 0); - }; - - handleClickOutside = () => { - this.setState({ visible: false }); - }; - - renderOverlay() { - return ( - <OutsideClickHandler onClickOutside={this.handleClickOutside}> - {({ ref }) => <div ref={ref}>{this.props.overlay}</div>} - </OutsideClickHandler> - ); - } - - render() { - return ( - <Tooltip classNameSpace="popup" overlay={this.renderOverlay()} visible={this.state.visible}> - {this.props.children({ onClick: this.handleClick })} - </Tooltip> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/Tooltip.css b/server/sonar-web/src/main/js/components/controls/Tooltip.css index bbb8ae5c942..9aeb7e42b3c 100644 --- a/server/sonar-web/src/main/js/components/controls/Tooltip.css +++ b/server/sonar-web/src/main/js/components/controls/Tooltip.css @@ -17,8 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -.tooltip, -.popup { +.tooltip { position: absolute; z-index: var(--tooltipZIndex); display: block; @@ -33,37 +32,27 @@ animation: fadeIn 0.3s forwards; } -.popup { - font-size: var(--baseFontSize); - font-weight: normal; -} - -.tooltip.top, -.popup.top { +.tooltip.top { padding: 5px 0; margin-top: -3px; } -.tooltip.right, -.popup.right { +.tooltip.right { padding: 0 5px; margin-left: 3px; } -.tooltip.bottom, -.popup.bottom { +.tooltip.bottom { padding: 5px 0; margin-top: 3px; } -.tooltip.left, -.popup.left { +.tooltip.left { padding: 0 5px; margin-left: -3px; } -.tooltip-inner, -.popup-inner { +.tooltip-inner { max-width: 300px; text-align: left; text-decoration: none; @@ -73,41 +62,34 @@ } .tooltip-inner { - padding: 3px 8px; + padding: 12px 17px; color: #fff; background-color: #475760; letter-spacing: 0.04em; } -.popup-inner { - padding: calc(2 * var(--gridSize)); - border: 1px solid var(--barBorderColor); - color: var(--baseFontColor); - background-color: #fff; - box-shadow: var(--defaultShadow); -} - .tooltip-inner .alert { margin-bottom: 5px; border-radius: 4px; } .tooltip-inner a { - color: var(--lightBlue); + border-bottom-color: #8da6b3; + color: #a5d0ea; +} + +.tooltip-inner hr { + background-color: #5d6d75; } -.tooltip-arrow, -.popup-arrow, -.popup-arrow::after { +.tooltip-arrow { position: absolute; width: 0; height: 0; border: solid transparent; } -.tooltip.top .tooltip-arrow, -.popup.top .popup-arrow, -.popup.top .popup-arrow::after { +.tooltip.top .tooltip-arrow { bottom: 0; left: 50%; border-width: 5px 5px 0; @@ -118,19 +100,7 @@ border-top-color: #475760; } -.popup.top .popup-arrow { - border-top-color: var(--barBorderColor); -} - -.popup.top .popup-arrow::after { - content: ''; - border-top-color: #fff; - transform: translateX(-5px) translateY(-1px); -} - -.tooltip.right .tooltip-arrow, -.popup.right .popup-arrow, -.popup.right .popup-arrow::after { +.tooltip.right .tooltip-arrow { top: 50%; left: 0; transform: translateY(-5px); @@ -142,19 +112,7 @@ border-right-color: #475760; } -.popup.right .popup-arrow { - border-right-color: var(--barBorderColor); -} - -.popup.right .popup-arrow::after { - content: ''; - border-right-color: #fff; - transform: translateY(-5px) translateX(1px); -} - -.tooltip.left .tooltip-arrow, -.popup.left .popup-arrow, -.popup.left .popup-arrow::after { +.tooltip.left .tooltip-arrow { top: 50%; right: 0; transform: translateY(-5px); @@ -166,19 +124,7 @@ border-left-color: #475760; } -.popup.left .popup-arrow { - border-left-color: var(--barBorderColor); -} - -.popup.left .popup-arrow::after { - content: ''; - border-left-color: #fff; - transform: translateY(-5px) translateX(-1px); -} - -.tooltip.bottom .tooltip-arrow, -.popup.bottom .popup-arrow, -.popup.bottom .popup-arrow::after { +.tooltip.bottom .tooltip-arrow { top: 0; left: 50%; transform: translateX(-5px); @@ -190,16 +136,6 @@ border-bottom-color: #475760; } -.popup.bottom .popup-arrow { - border-bottom-color: var(--barBorderColor); -} - -.popup.bottom .popup-arrow::after { - content: ''; - border-bottom-color: #fff; - transform: translateX(-5px) translateY(1px); -} - @keyframes fadeIn { from { opacity: 0; diff --git a/server/sonar-web/src/main/js/components/controls/Tooltip.tsx b/server/sonar-web/src/main/js/components/controls/Tooltip.tsx index adc29a6270e..ca6803887e9 100644 --- a/server/sonar-web/src/main/js/components/controls/Tooltip.tsx +++ b/server/sonar-web/src/main/js/components/controls/Tooltip.tsx @@ -28,6 +28,7 @@ interface Props { classNameSpace?: string; children: React.ReactElement<{}>; mouseEnterDelay?: number; + mouseLeaveDelay?: number; onShow?: () => void; onHide?: () => void; overlay: React.ReactNode; @@ -65,8 +66,10 @@ export default function Tooltip(props: Props) { export class TooltipInner extends React.Component<Props, State> { throttledPositionTooltip: (() => void); mouseEnterInterval?: number; + mouseLeaveInterval?: number; tooltipNode?: HTMLElement | null; mounted = false; + mouseIn = false; static defaultProps = { mouseEnterDelay: 0.1 @@ -113,6 +116,7 @@ export class TooltipInner extends React.Component<Props, State> { componentWillUnmount() { this.mounted = false; this.removeEventListeners(); + this.clearIntervals(); } addEventListeners = () => { @@ -125,6 +129,11 @@ export class TooltipInner extends React.Component<Props, State> { window.removeEventListener('scroll', this.throttledPositionTooltip); }; + clearIntervals = () => { + window.clearInterval(this.mouseEnterInterval); + window.clearInterval(this.mouseLeaveInterval); + }; + isVisible = () => { return this.props.visible !== undefined ? this.props.visible : this.state.visible; }; @@ -235,15 +244,31 @@ export class TooltipInner extends React.Component<Props, State> { window.clearInterval(this.mouseEnterInterval); this.mouseEnterInterval = undefined; } - if (this.props.visible === undefined) { - this.setState({ visible: false }); - } - if (this.props.onHide) { - this.props.onHide(); + if (!this.mouseIn) { + this.mouseLeaveInterval = window.setTimeout(() => { + if (this.mounted) { + if (this.props.visible === undefined && !this.mouseIn) { + this.setState({ visible: false }); + } + } + }, (this.props.mouseLeaveDelay || 0) * 1000); + + if (this.props.onHide) { + this.props.onHide(); + } } }; + handleOverlayMouseEnter = () => { + this.mouseIn = true; + }; + + handleOverlayMouseLeave = () => { + this.mouseIn = false; + this.handleMouseLeave(); + }; + render() { const { classNameSpace = 'tooltip' } = this.props; @@ -257,6 +282,8 @@ export class TooltipInner extends React.Component<Props, State> { <TooltipPortal> <div className={`${classNameSpace} ${this.getPlacement()}`} + onMouseEnter={this.handleOverlayMouseEnter} + onMouseLeave={this.handleOverlayMouseLeave} ref={this.tooltipNodeRef} style={ isMeasured(this.state) diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx index 0f4bbb02ba0..f0b1f65f860 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx @@ -56,6 +56,8 @@ it('should open & close', () => { expect(onShow).toBeCalled(); wrapper.find('#tooltip').simulate('mouseleave'); + jest.runOnlyPendingTimers(); + wrapper.update(); expect(wrapper).toMatchSnapshot(); expect(onHide).toBeCalled(); }); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap index f7e3657057c..4a369aceaa4 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap @@ -10,6 +10,8 @@ exports[`should open & close 1`] = ` <TooltipPortal> <div className="tooltip bottom" + onMouseEnter={[Function]} + onMouseLeave={[Function]} > <div className="tooltip-inner" @@ -56,6 +58,8 @@ exports[`should render 2`] = ` <TooltipPortal> <div className="tooltip bottom" + onMouseEnter={[Function]} + onMouseLeave={[Function]} > <div className="tooltip-inner" diff --git a/server/sonar-web/src/main/js/components/docs/DocImg.tsx b/server/sonar-web/src/main/js/components/docs/DocImg.tsx index cafed4edcd0..d055c6cf16a 100644 --- a/server/sonar-web/src/main/js/components/docs/DocImg.tsx +++ b/server/sonar-web/src/main/js/components/docs/DocImg.tsx @@ -18,13 +18,21 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import { getBaseUrl } from '../../helpers/urls'; export default function DocImg(props: React.ImgHTMLAttributes<HTMLImageElement>) { const { alt, src, ...other } = props; if (process.env.NODE_ENV === 'development') { - return <img alt={alt} className="max-width-100" src={src} {...other} />; + return <img alt={alt} className="max-width-100" src={getBaseUrl() + src} {...other} />; } - return <img alt={alt} className="max-width-100" src={'/images/embed-doc' + src} {...other} />; + return ( + <img + alt={alt} + className="max-width-100" + src={getBaseUrl() + '/images/embed-doc' + src} + {...other} + /> + ); } diff --git a/server/sonar-web/src/main/js/components/docs/DocInclude.tsx b/server/sonar-web/src/main/js/components/docs/DocInclude.tsx index d90d893a0bd..85298633439 100644 --- a/server/sonar-web/src/main/js/components/docs/DocInclude.tsx +++ b/server/sonar-web/src/main/js/components/docs/DocInclude.tsx @@ -21,6 +21,7 @@ import * as React from 'react'; import DocMarkdownBlock from './DocMarkdownBlock'; interface Props { + className?: string; path: string; } @@ -67,6 +68,6 @@ export default class DocInclude extends React.PureComponent<Props, State> { }; render() { - return <DocMarkdownBlock content={this.state.content} />; + return <DocMarkdownBlock className={this.props.className} content={this.state.content} />; } } diff --git a/server/sonar-web/src/main/js/components/docs/DocLink.tsx b/server/sonar-web/src/main/js/components/docs/DocLink.tsx index 17b99af9c4e..5e741918f95 100644 --- a/server/sonar-web/src/main/js/components/docs/DocLink.tsx +++ b/server/sonar-web/src/main/js/components/docs/DocLink.tsx @@ -19,6 +19,7 @@ */ import * as React from 'react'; import { Link } from 'react-router'; +import DetachIcon from '../../components/icons-components/DetachIcon'; export default function DocLink(props: React.AnchorHTMLAttributes<HTMLAnchorElement>) { const { children, href, ...other } = props; @@ -32,8 +33,14 @@ export default function DocLink(props: React.AnchorHTMLAttributes<HTMLAnchorElem } return ( - <a href={href} {...other}> - {children} - </a> + <> + <a className="text-middle" href={href} rel="noopener noreferrer" target="_blank" {...other}> + {children} + </a> + <DetachIcon + className="text-middle text-muted little-spacer-left little-spacer-right" + size={12} + /> + </> ); } diff --git a/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx b/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx index 5c719443490..e064f15d2ee 100644 --- a/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx +++ b/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx @@ -18,15 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as classNames from 'classnames'; import DocMarkdownBlock from './DocMarkdownBlock'; -import HelpIcon from '../icons-components/HelpIcon'; -import Tooltip from '../controls/Tooltip'; -import OutsideClickHandler from '../controls/OutsideClickHandler'; -import * as theme from '../../app/theme'; +import HelpTooltip from '../controls/HelpTooltip'; interface Props { className?: string; + children?: React.ReactNode; /** Key of the documentation chunk */ doc: string; } @@ -77,23 +74,6 @@ export default class DocTooltip extends React.PureComponent<Props, State> { this.setState({ open: false }); }; - handleHelpClick = (event: React.MouseEvent<HTMLAnchorElement>) => { - event.preventDefault(); - event.currentTarget.blur(); - if (!this.state.open && !this.state.loading && this.state.content === undefined) { - this.fetchContent(); - } - - if (this.state.open) { - this.setState({ open: false }); - } else { - // defer opening to not trigger OutsideClickHandler.onClickOutside callback - setTimeout(() => { - this.setState({ open: true }); - }, 0); - } - }; - renderOverlay() { if (this.state.loading) { return ( @@ -103,32 +83,17 @@ export default class DocTooltip extends React.PureComponent<Props, State> { ); } - return ( - <OutsideClickHandler onClickOutside={this.close}> - {({ ref }) => ( - <div ref={ref}> - <DocMarkdownBlock className="cut-margins abs-width-300" content={this.state.content} /> - </div> - )} - </OutsideClickHandler> - ); + return <DocMarkdownBlock className="cut-margins abs-width-300" content={this.state.content} />; } render() { return ( - <div className={classNames('display-flex-center', this.props.className)}> - <Tooltip - classNameSpace="popup" - overlay={this.renderOverlay()} - visible={this.state.content !== undefined && this.state.open}> - <a - className="display-flex-center link-no-underline" - href="#" - onClick={this.handleHelpClick}> - <HelpIcon fill={theme.gray80} size={12} /> - </a> - </Tooltip> - </div> + <HelpTooltip + className={this.props.className} + onShow={this.fetchContent} + overlay={this.renderOverlay()}> + {this.props.children} + </HelpTooltip> ); } } diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx index bc5b4998cc7..570b68e37c0 100644 --- a/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx +++ b/server/sonar-web/src/main/js/components/docs/__tests__/DocTooltip-test.tsx @@ -20,7 +20,6 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import DocTooltip from '../DocTooltip'; -import { click } from '../../../helpers/testUtils'; jest.useFakeTimers(); @@ -38,11 +37,3 @@ it('should reset state when receiving new doc', () => { wrapper.setProps({ doc: 'baz' }); expect(wrapper.state()).toEqual({ content: undefined, loading: false, open: false }); }); - -it('should toggle', () => { - const wrapper = shallow(<DocTooltip doc="foo/bar" />); - expect(wrapper.state('open')).toBe(false); - click(wrapper.find('a')); - jest.runAllTimers(); - expect(wrapper.state('open')).toBe(true); -}); diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap index 97a6d1d24bc..d5678b25137 100644 --- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocLink-test.tsx.snap @@ -1,7 +1,16 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should render simple link 1`] = ` -<a - href="http://sample.com" -/> +<React.Fragment> + <a + className="text-middle" + href="http://sample.com" + rel="noopener noreferrer" + target="_blank" + /> + <DetachIcon + className="text-middle text-muted little-spacer-left little-spacer-right" + size={12} + /> +</React.Fragment> `; diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap index 38e7789c044..cbdf355d855 100644 --- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap @@ -1,61 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should render 1`] = ` -<div - className="display-flex-center" -> - <Tooltip - classNameSpace="popup" - overlay={ - <div - className="abs-width-300" - > - <i - className="spinner" - /> - </div> - } - visible={true} - > - <a - className="display-flex-center link-no-underline" - href="#" - onClick={[Function]} +<HelpTooltip + onShow={[Function]} + overlay={ + <div + className="abs-width-300" > - <HelpIcon - fill="#cdcdcd" - size={12} + <i + className="spinner" /> - </a> - </Tooltip> -</div> + </div> + } +/> `; exports[`should render 2`] = ` -<div - className="display-flex-center" -> - <Tooltip - classNameSpace="popup" - overlay={ - <OutsideClickHandler - onClickOutside={[Function]} - > - [Function] - </OutsideClickHandler> - } - visible={true} - > - <a - className="display-flex-center link-no-underline" - href="#" - onClick={[Function]} - > - <HelpIcon - fill="#cdcdcd" - size={12} - /> - </a> - </Tooltip> -</div> +<HelpTooltip + onShow={[Function]} + overlay={ + <DocMarkdownBlock + className="cut-margins abs-width-300" + content="this is *bold* text" + /> + } +/> `; diff --git a/server/sonar-web/src/main/js/components/facet/FacetHeader.tsx b/server/sonar-web/src/main/js/components/facet/FacetHeader.tsx index cc1ae72047a..f4544cf5028 100644 --- a/server/sonar-web/src/main/js/components/facet/FacetHeader.tsx +++ b/server/sonar-web/src/main/js/components/facet/FacetHeader.tsx @@ -19,8 +19,7 @@ */ import * as React from 'react'; import OpenCloseIcon from '../icons-components/OpenCloseIcon'; -import HelpIcon from '../icons-components/HelpIcon'; -import Tooltip from '../controls/Tooltip'; +import HelpTooltip from '../controls/HelpTooltip'; import { Button } from '../ui/buttons'; import { translate, translateWithParameters } from '../../helpers/l10n'; @@ -47,13 +46,7 @@ export default class FacetHeader extends React.PureComponent<Props> { if (!this.props.helper) { return null; } - return ( - <Tooltip overlay={this.props.helper}> - <span> - <HelpIcon className="spacer-left text-info" /> - </span> - </Tooltip> - ); + return <HelpTooltip className="spacer-left" overlay={this.props.helper} />; } renderValueIndicator() { @@ -77,7 +70,7 @@ export default class FacetHeader extends React.PureComponent<Props> { return ( <div className="search-navigator-facet-header-wrapper"> {this.props.onClick ? ( - <span className="search-navigator-facet-header"> + <span className="search-navigator-facet-header display-flex-center"> <a href="#" onClick={this.handleClick}> <OpenCloseIcon className="little-spacer-right" open={this.props.open} /> {this.props.name} @@ -85,7 +78,7 @@ export default class FacetHeader extends React.PureComponent<Props> { {this.renderHelper()} </span> ) : ( - <span className="search-navigator-facet-header"> + <span className="search-navigator-facet-header display-flex-center"> {this.props.name} {this.renderHelper()} </span> diff --git a/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap b/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap index e68fe594ca1..4dba5b7b374 100644 --- a/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/facet/__tests__/__snapshots__/FacetHeader-test.tsx.snap @@ -5,7 +5,7 @@ exports[`should clear 1`] = ` className="search-navigator-facet-header-wrapper" > <span - className="search-navigator-facet-header" + className="search-navigator-facet-header display-flex-center" > <a href="#" @@ -42,7 +42,7 @@ exports[`should render closed facet with value 1`] = ` className="search-navigator-facet-header-wrapper" > <span - className="search-navigator-facet-header" + className="search-navigator-facet-header display-flex-center" > <a href="#" @@ -73,7 +73,7 @@ exports[`should render closed facet without value 1`] = ` className="search-navigator-facet-header-wrapper" > <span - className="search-navigator-facet-header" + className="search-navigator-facet-header display-flex-center" > <a href="#" @@ -97,7 +97,7 @@ exports[`should render open facet with value 1`] = ` className="search-navigator-facet-header-wrapper" > <span - className="search-navigator-facet-header" + className="search-navigator-facet-header display-flex-center" > <a href="#" @@ -121,7 +121,7 @@ exports[`should render open facet without value 1`] = ` className="search-navigator-facet-header-wrapper" > <span - className="search-navigator-facet-header" + className="search-navigator-facet-header display-flex-center" > <a href="#" @@ -145,7 +145,7 @@ exports[`should render without link 1`] = ` className="search-navigator-facet-header-wrapper" > <span - className="search-navigator-facet-header" + className="search-navigator-facet-header display-flex-center" > foo </span> diff --git a/server/sonar-web/src/main/js/components/icons-components/HelpIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/HelpIcon.tsx index 80170315190..8a2d9394501 100644 --- a/server/sonar-web/src/main/js/components/icons-components/HelpIcon.tsx +++ b/server/sonar-web/src/main/js/components/icons-components/HelpIcon.tsx @@ -24,16 +24,16 @@ export default function HelpIcon({ className, fill = 'currentColor', size = 16 } return ( <svg className={className} - width={size} height={size} - viewBox="0 0 16 16" version="1.1" - xmlnsXlink="http://www.w3.org/1999/xlink" - xmlSpace="preserve"> + viewBox="0 0 16 16" + width={size} + xmlSpace="preserve" + xmlnsXlink="http://www.w3.org/1999/xlink"> <g transform="matrix(0.0364583,0,0,0.0364583,1,-0.166667)"> <path - style={{ fill }} d="M224,344L224,296C224,293.667 223.25,291.75 221.75,290.25C220.25,288.75 218.333,288 216,288L168,288C165.667,288 163.75,288.75 162.25,290.25C160.75,291.75 160,293.667 160,296L160,344C160,346.333 160.75,348.25 162.25,349.75C163.75,351.25 165.667,352 168,352L216,352C218.333,352 220.25,351.25 221.75,349.75C223.25,348.25 224,346.333 224,344ZM288,176C288,161.333 283.375,147.75 274.125,135.25C264.875,122.75 253.333,113.083 239.5,106.25C225.667,99.417 211.5,96 197,96C156.5,96 125.583,113.75 104.25,149.25C101.75,153.25 102.417,156.75 106.25,159.75L139.25,184.75C140.417,185.75 142,186.25 144,186.25C146.667,186.25 148.75,185.25 150.25,183.25C159.083,171.917 166.25,164.25 171.75,160.25C177.417,156.25 184.583,154.25 193.25,154.25C201.25,154.25 208.375,156.417 214.625,160.75C220.875,165.083 224,170 224,175.5C224,181.833 222.333,186.917 219,190.75C215.667,194.583 210,198.333 202,202C191.5,206.667 181.875,213.875 173.125,223.625C164.375,233.375 160,243.833 160,255L160,264C160,266.333 160.75,268.25 162.25,269.75C163.75,271.25 165.667,272 168,272L216,272C218.333,272 220.25,271.25 221.75,269.75C223.25,268.25 224,266.333 224,264C224,260.833 225.792,256.708 229.375,251.625C232.958,246.542 237.5,242.417 243,239.25C248.333,236.25 252.417,233.875 255.25,232.125C258.083,230.375 261.917,227.458 266.75,223.375C271.583,219.292 275.292,215.292 277.875,211.375C280.458,207.458 282.792,202.417 284.875,196.25C286.958,190.083 288,183.333 288,176ZM384,224C384,258.833 375.417,290.958 358.25,320.375C341.083,349.792 317.792,373.083 288.375,390.25C258.958,407.417 226.833,416 192,416C157.167,416 125.042,407.417 95.625,390.25C66.208,373.083 42.917,349.792 25.75,320.375C8.583,290.958 0,258.833 0,224C0,189.167 8.583,157.042 25.75,127.625C42.917,98.208 66.208,74.917 95.625,57.75C125.042,40.583 157.167,32 192,32C226.833,32 258.958,40.583 288.375,57.75C317.792,74.917 341.083,98.208 358.25,127.625C375.417,157.042 384,189.167 384,224Z" + style={{ fill }} /> </g> </svg> diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 5297bb3bedd..9d48f94d81c 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2559,11 +2559,11 @@ organization.change_visibility_form.submit=Change Default Visibility # #------------------------------------------------------------------------------ embed_docs.suggestion=Suggestions For This Page -embed_docs.documentation_index=Documentation index +embed_docs.documentation=Documentation embed_docs.get_support=Get Support embed_docs.stay_connected=Stay Connected -embed_docs.contact_form=Contact form -embed_docs.analyze_new_project=Analyze new project +embed_docs.contact_form=Contact Form +embed_docs.analyze_new_project=Analyze New Project #------------------------------------------------------------------------------ # @@ -2679,8 +2679,6 @@ onboarding.project_watcher.failed=Something went wrong, please check the analysi # BRANCHES # #------------------------------------------------------------------------------ -branches.learn_how_to_analyze=Learn how to analyze branches in SonarQube -branches.learn_how_to_analyze.text=Quickly setup branch analysis and get separate insights for each of your branches and pull requests. branches.delete=Delete Branch branches.delete.are_you_sure=Are you sure you want to delete branch "{0}"? branches.pull_request.delete=Delete Pull Request @@ -2697,8 +2695,6 @@ branches.detection_of_long_living_branches=Detection of long living branches branches.detection_of_long_living_branches.description=Regular expression used to detect whether a branch is a long living branch (as opposed to short living branch), based on its name. This applies only during first analysis, the type of a branch cannot be changed later. branches.set_leak_period=Set Leak Period branches.last_analysis_date=Last Analysis Date -branches.no_support.header=Get the most out of SonarQube with branches analysis -branches.no_support.header.text=Analyze each branch of your project separately with the Developer Edition. branches.search_for_branches=Search for branches... branches.pull_requests=Pull Requests branches.short_lived.quality_gate.description=The branch status is passed because there are no open issue. The remaining {0} issue(s) have been confirmed. |