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() {
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 });
}
});
};
}
.navbar-context-meta-branch {
- margin-top: 20px;
+ margin-top: 3px;
line-height: 16px;
}
};
static contextTypes = {
- branchesEnabled: PropTypes.bool.isRequired
+ branchesEnabled: PropTypes.bool.isRequired,
+ onSonarCloud: PropTypes.bool
};
componentDidMount() {
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">
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 {
})}
/>
{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} />
renderAdministration() {
const { branch } = this.props;
- if (branch && isShortLivingBranch(branch)) {
+ if (!this.props.conf.showSettings || (branch && isShortLivingBranch(branch))) {
return null;
}
* 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';
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>
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>
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>
);
}
- if (props.component.analysisDate && !shortBranch) {
+ if (props.component.analysisDate) {
metaList.push(
<li key="analysisDate">
<DateTimeFormatter date={props.component.analysisDate} />
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>
);
}
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();
+});
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()
+ );
});
className="little-spacer-right"
/>
master
+ <div
+ className="outline-badge spacer-left"
+ >
+ branches.main_branch
+ </div>
</div>
<div
className="big-spacer-left note"
</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>
<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>
`;
})}
/>
{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} />
className="little-spacer-right"
/>
master
+ <div
+ className="outline-badge spacer-left"
+ >
+ branches.main_branch
+ </div>
</td>
<td
className="thin nowrap text-right"
// @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';
<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">
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