@@ -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) |
@@ -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) |
@@ -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); | |||
} | |||
@@ -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> |
@@ -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 |
@@ -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(); | |||
}); |
@@ -48,7 +48,7 @@ exports[`should display suggestion links 1`] = ` | |||
style={Object {}} | |||
to="/documentation" | |||
> | |||
embed_docs.documentation_index | |||
embed_docs.documentation | |||
</Link> | |||
</li> | |||
<li> | |||
@@ -110,6 +110,9 @@ exports[`should display suggestion links 1`] = ` | |||
Stack Overflow | |||
</a> | |||
</li> | |||
<li | |||
className="divider" | |||
/> | |||
<li | |||
className="dropdown-header" | |||
> |
@@ -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> | |||
); | |||
} |
@@ -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 && ( |
@@ -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> | |||
</> | |||
); | |||
} |
@@ -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', () => { |
@@ -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> | |||
`; |
@@ -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={ |
@@ -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> | |||
`; |
@@ -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> | |||
`; |
@@ -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} |
@@ -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); |
@@ -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, |
@@ -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> | |||
</> | |||
); | |||
} |
@@ -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} />} |
@@ -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> |
@@ -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"> |
@@ -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> | |||
); |
@@ -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; | |||
} |
@@ -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 |
@@ -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> | |||
)} | |||
@@ -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> | |||
`; |
@@ -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> | |||
)); | |||
@@ -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> | |||
); |
@@ -29,5 +29,5 @@ | |||
} | |||
.permissions-table .permission-column-inner { | |||
width: 112px; | |||
width: 100px; | |||
} |
@@ -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 |
@@ -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={ |
@@ -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"> |
@@ -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 && ( |
@@ -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 |
@@ -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 |
@@ -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; | |||
@@ -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" |
@@ -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>; | |||
} |
@@ -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"> |
@@ -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> |
@@ -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>; |
@@ -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> |
@@ -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" |
@@ -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> |
@@ -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" |
@@ -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={ |
@@ -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> | |||
); | |||
} | |||
@@ -63,8 +63,8 @@ | |||
.oauth-providers-help { | |||
position: absolute; | |||
top: 12px; | |||
right: -32px; | |||
top: 15px; | |||
right: -24px; | |||
} | |||
.oauth-providers + .login-form { |
@@ -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> | |||
); |
@@ -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> | |||
`; | |||
@@ -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> | |||
); |
@@ -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> | |||
`; |
@@ -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> | |||
) | |||
}} | |||
/> |
@@ -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>, | |||
} | |||
} | |||
/> |
@@ -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> | |||
); |
@@ -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> | |||
`; |
@@ -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; | |||
} |
@@ -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> | |||
); | |||
} |
@@ -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> | |||
); | |||
} | |||
} |
@@ -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; |
@@ -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) |
@@ -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(); | |||
}); |
@@ -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" |
@@ -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} | |||
/> | |||
); | |||
} |
@@ -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} />; | |||
} | |||
} |
@@ -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} | |||
/> | |||
</> | |||
); | |||
} |
@@ -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> | |||
); | |||
} | |||
} |
@@ -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); | |||
}); |
@@ -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> | |||
`; |
@@ -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" | |||
/> | |||
} | |||
/> | |||
`; |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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. |