diff options
15 files changed, 204 insertions, 45 deletions
diff --git a/server/sonar-web/src/main/js/app/components/App.tsx b/server/sonar-web/src/main/js/app/components/App.tsx index 400ab16b2ae..46cd8a6f620 100644 --- a/server/sonar-web/src/main/js/app/components/App.tsx +++ b/server/sonar-web/src/main/js/app/components/App.tsx @@ -34,18 +34,20 @@ interface Props { interface State { branchesEnabled: boolean; loading: boolean; + onSonarCloud: boolean; } class App extends React.PureComponent<Props, State> { mounted: boolean; - state: State = { branchesEnabled: false, loading: true }; + state: State = { branchesEnabled: false, loading: true, onSonarCloud: false }; static childContextTypes = { - branchesEnabled: PropTypes.bool.isRequired + branchesEnabled: PropTypes.bool.isRequired, + onSonarCloud: PropTypes.bool }; getChildContext() { - return { branchesEnabled: this.state.branchesEnabled }; + return { branchesEnabled: this.state.branchesEnabled, onSonarCloud: this.state.onSonarCloud }; } componentDidMount() { @@ -64,7 +66,10 @@ class App extends React.PureComponent<Props, State> { fetchAppState = () => { return this.props.fetchAppState().then(appState => { if (this.mounted) { - this.setState({ branchesEnabled: appState.branchesEnabled }); + const onSonarCloud = + appState.settings != undefined && + appState.settings['sonar.lf.sonarqube.com.enabled'] === 'true'; + this.setState({ branchesEnabled: appState.branchesEnabled, onSonarCloud }); } }); }; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css index e29574c39e4..5f3958f35bd 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css @@ -18,7 +18,7 @@ } .navbar-context-meta-branch { - margin-top: 20px; + margin-top: 3px; line-height: 16px; } 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 93961a70548..c59cebdd6f8 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 @@ -53,7 +53,8 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State }; static contextTypes = { - branchesEnabled: PropTypes.bool.isRequired + branchesEnabled: PropTypes.bool.isRequired, + onSonarCloud: PropTypes.bool }; componentDidMount() { @@ -172,6 +173,10 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State render() { const { branches, currentBranch } = this.props; + if (this.context.onSonarCloud && !this.context.branchesEnabled) { + return null; + } + if (!this.context.branchesEnabled) { return ( <div className="navbar-context-branches"> diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenuItem.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenuItem.tsx index ece4360a4dc..40fa2ec46fb 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenuItem.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenuItem.tsx @@ -24,6 +24,7 @@ import BranchStatus from '../../../../components/common/BranchStatus'; import { Branch, Component } from '../../../types'; import BranchIcon from '../../../../components/icons-components/BranchIcon'; import { isShortLivingBranch } from '../../../../helpers/branches'; +import { translate } from '../../../../helpers/l10n'; import { getProjectBranchUrl } from '../../../../helpers/urls'; interface Props { @@ -53,6 +54,10 @@ export default function ComponentNavBranchesMenuItem({ branch, ...props }: Props })} /> {branch.name} + {branch.isMain && + <div className="outline-badge spacer-left"> + {translate('branches.main_branch')} + </div>} </div> <div className="big-spacer-left note"> <BranchStatus branch={branch} concise={true} /> diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx index af1ef904984..69f0fd45640 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx @@ -191,7 +191,7 @@ export default class ComponentNavMenu extends React.PureComponent<Props> { renderAdministration() { const { branch } = this.props; - if (branch && isShortLivingBranch(branch)) { + if (!this.props.conf.showSettings || (branch && isShortLivingBranch(branch))) { return null; } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx index ecf5562b8b9..9f8c46a43e8 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as classNames from 'classnames'; import IncrementalBadge from './IncrementalBadge'; import BranchStatus from '../../../../components/common/BranchStatus'; import { Branch, Component, ComponentConfiguration } from '../../../types'; @@ -56,7 +55,7 @@ export default function ComponentNavMeta(props: Props) { key="isInProgress" overlay={<div dangerouslySetInnerHTML={{ __html: tooltip }} />} mouseLeaveDelay={2}> - <li className={classNames({ 'navbar-context-meta-branch': shortBranch })}> + <li> <i className="spinner" style={{ marginTop: '-1px' }} />{' '} <span className="text-info">{translate('background_task.status.IN_PROGRESS')}</span> </li> @@ -71,7 +70,7 @@ export default function ComponentNavMeta(props: Props) { key="isPending" overlay={<div dangerouslySetInnerHTML={{ __html: tooltip }} />} mouseLeaveDelay={2}> - <li className={classNames({ 'navbar-context-meta-branch': shortBranch })}> + <li> <PendingIcon /> <span>{translate('background_task.status.PENDING')}</span> </li> </Tooltip> @@ -85,7 +84,7 @@ export default function ComponentNavMeta(props: Props) { key="isFailed" overlay={<div dangerouslySetInnerHTML={{ __html: tooltip }} />} mouseLeaveDelay={2}> - <li className={classNames({ 'navbar-context-meta-branch': shortBranch })}> + <li> <span className="badge badge-danger"> {translate('background_task.status.FAILED')} </span> @@ -94,7 +93,7 @@ export default function ComponentNavMeta(props: Props) { ); } - if (props.component.analysisDate && !shortBranch) { + if (props.component.analysisDate) { metaList.push( <li key="analysisDate"> <DateTimeFormatter date={props.component.analysisDate} /> @@ -112,25 +111,21 @@ export default function ComponentNavMeta(props: Props) { if (props.incremental) { metaList.push( - <li key="incremental" className={classNames({ 'navbar-context-meta-branch': shortBranch })}> + <li key="incremental"> <IncrementalBadge /> </li> ); } - if (shortBranch) { - metaList.push( - <li className="navbar-context-meta-branch" key="branch-status"> - <BranchStatus branch={props.branch!} /> - </li> - ); - } - return ( <div className="navbar-context-meta"> <ul className="list-inline"> {metaList} </ul> + {shortBranch && + <div className="navbar-context-meta-branch"> + <BranchStatus branch={props.branch!} /> + </div>} </div> ); } 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 9f3a4e429c8..28931e0fc51 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 @@ -112,3 +112,13 @@ it('renders no branch support popup', () => { click(wrapper.find('a')); expect(wrapper.find('BubblePopupHelper').prop('isOpen')).toBe(true); }); + +it('renders nothing on SonarCloud without branch support', () => { + const branch: MainBranch = { isMain: true, name: 'master' }; + const component = {} as Component; + const wrapper = shallow( + <ComponentNavBranch branches={[branch]} currentBranch={branch} project={component} />, + { context: { branchesEnabled: false, onSonarCloud: true } } + ); + expect(wrapper.type()).toBeNull(); +}); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx index 0c50f2de673..ad86f8f2246 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx @@ -91,10 +91,11 @@ it('should work for short-living branches', () => { it('should work for long-living branches', () => { const branch: LongLivingBranch = { isMain: false, name: 'release', type: BranchType.LONG }; const component = { key: 'foo', qualifier: 'TRK' } as Component; - const conf = { showSettings: true }; - expect( - shallow(<ComponentNavMenu branch={branch} component={component} conf={conf} />, { - context: { branchesEnabled: true } - }) - ).toMatchSnapshot(); + [true, false].forEach(showSettings => + expect( + shallow(<ComponentNavMenu branch={branch} component={component} conf={{ showSettings }} />, { + context: { branchesEnabled: true } + }) + ).toMatchSnapshot() + ); }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenuItem-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenuItem-test.tsx.snap index c1aed6ae1b6..f4edb48406f 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenuItem-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenuItem-test.tsx.snap @@ -28,6 +28,11 @@ exports[`renders main branch 1`] = ` className="little-spacer-right" /> master + <div + className="outline-badge spacer-left" + > + branches.main_branch + </div> </div> <div className="big-spacer-left note" diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap index bad199992da..1cb875eee66 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap @@ -116,6 +116,102 @@ exports[`should work for long-living branches 1`] = ` </NavBarTabs> `; +exports[`should work for long-living branches 2`] = ` +<NavBarTabs> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to={ + Object { + "pathname": "/dashboard", + "query": Object { + "branch": "release", + "id": "foo", + }, + } + } + > + overview.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to={ + Object { + "pathname": "/project/issues", + "query": Object { + "branch": "release", + "id": "foo", + "resolved": "false", + }, + } + } + > + issues.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to={ + Object { + "pathname": "/component_measures", + "query": Object { + "branch": "release", + "id": "foo", + }, + } + } + > + layout.measures + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to={ + Object { + "pathname": "/code", + "query": Object { + "branch": "release", + "id": "foo", + }, + } + } + > + code.page + </Link> + </li> + <li> + <Link + activeClassName="active" + onlyActiveOnIndex={false} + style={Object {}} + to={ + Object { + "pathname": "/project/activity", + "query": Object { + "branch": "release", + "id": "foo", + }, + } + } + > + project_activity.page + </Link> + </li> +</NavBarTabs> +`; + exports[`should work for short-living branches 1`] = ` <NavBarTabs> <li> diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap index 97421e0df87..9639b62f57f 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap @@ -27,25 +27,30 @@ exports[`renders status of short-living branch 1`] = ` <ul className="list-inline" > - <li - className="navbar-context-meta-branch" - > - <BranchStatus - branch={ - Object { - "isMain": false, - "mergeBranch": "master", - "name": "feature", - "status": Object { - "bugs": 0, - "codeSmells": 2, - "vulnerabilities": 3, - }, - "type": "SHORT", - } - } + <li> + <DateTimeFormatter + date="2017-01-02T00:00:00.000Z" /> </li> </ul> + <div + className="navbar-context-meta-branch" + > + <BranchStatus + branch={ + Object { + "isMain": false, + "mergeBranch": "master", + "name": "feature", + "status": Object { + "bugs": 0, + "codeSmells": 2, + "vulnerabilities": 3, + }, + "type": "SHORT", + } + } + /> + </div> </div> `; diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/BranchRow.tsx b/server/sonar-web/src/main/js/apps/projectBranches/components/BranchRow.tsx index b8bba666f10..0cc92e8008e 100644 --- a/server/sonar-web/src/main/js/apps/projectBranches/components/BranchRow.tsx +++ b/server/sonar-web/src/main/js/apps/projectBranches/components/BranchRow.tsx @@ -93,6 +93,10 @@ export default class BranchRow extends React.PureComponent<Props, State> { })} /> {branch.name} + {branch.isMain && + <div className="outline-badge spacer-left"> + {translate('branches.main_branch')} + </div>} </td> <td className="thin nowrap text-right"> <BranchStatus branch={branch} /> diff --git a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/BranchRow-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/BranchRow-test.tsx.snap index f31097d6911..ea135765ece 100644 --- a/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/BranchRow-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/BranchRow-test.tsx.snap @@ -13,6 +13,11 @@ exports[`renders main branch 1`] = ` className="little-spacer-right" /> master + <div + className="outline-badge spacer-left" + > + branches.main_branch + </div> </td> <td className="thin nowrap text-right" diff --git a/server/sonar-web/src/main/js/apps/settings/components/App.js b/server/sonar-web/src/main/js/apps/settings/components/App.js index 2e53e8c87ab..4f466e19461 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/App.js +++ b/server/sonar-web/src/main/js/apps/settings/components/App.js @@ -20,6 +20,8 @@ // @flow import React from 'react'; import Helmet from 'react-helmet'; +import { Link } from 'react-router'; +import { FormattedMessage } from 'react-intl'; import PageHeader from './PageHeader'; import CategoryDefinitionsList from './CategoryDefinitionsList'; import AllCategoriesList from './AllCategoriesList'; @@ -87,7 +89,25 @@ export default class App extends React.PureComponent { <div id="settings-page" className="page page-limited"> <Helmet title={translate('settings.page')} /> - {branchName == null && <PageHeader branch={branchName} component={this.props.component} />} + {branchName + ? <div className="alert alert-info"> + <FormattedMessage + defaultMessage={translate('branches.settings_hint')} + id="branches.settings_hint" + values={{ + link: ( + <Link + to={{ + pathname: '/project/branches', + query: { id: this.props.component && this.props.component.key } + }}> + {translate('branches.settings_hint_tab')} + </Link> + ) + }} + /> + </div> + : <PageHeader branch={branchName} component={this.props.component} />} <div className="side-tabs-layout settings-layout"> {branchName == null && <div className="side-tabs-side"> 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 655f063d4c7..78a96970467 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -3173,3 +3173,6 @@ branches.manage=Manage branches branches.orphan_branch=Orphan Branch branches.orphan_branches=Orphan Branches branches.orphan_branches.tooltip=When a target branch of a short-living branch was deleted, this short-living branch becomes orphan. +branches.main_branch=Main Branch +branches.settings_hint=To administrate your branches, you have to go to your main branch's {link} tab. +branches.settings_hint_tab=Administration > Branches |