]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9702 SONAR-9736 apply feedback on branches (#2496)
authorStas Vilchik <stas.vilchik@sonarsource.com>
Mon, 11 Sep 2017 13:02:01 +0000 (15:02 +0200)
committerJanos Gyerik <janos.gyerik@sonarsource.com>
Tue, 12 Sep 2017 09:34:59 +0000 (11:34 +0200)
* show last analysis date for short-living branches
* put "main branch" badge
* display hint on branch administration page
* hide anything related to branches on sonarcloud without branch support

* fixup! fix showing administration on branch

15 files changed:
server/sonar-web/src/main/js/app/components/App.tsx
server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranchesMenuItem.tsx
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenuItem-test.tsx.snap
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap
server/sonar-web/src/main/js/apps/projectBranches/components/BranchRow.tsx
server/sonar-web/src/main/js/apps/projectBranches/components/__tests__/__snapshots__/BranchRow-test.tsx.snap
server/sonar-web/src/main/js/apps/settings/components/App.js
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 400ab16b2aea8387f19ab9eec4a611947b22830e..46cd8a6f620a2b45ab674e9f690ce383e967d73f 100644 (file)
@@ -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 });
       }
     });
   };
index e29574c39e489222a2f6361798e7c5c1aee8f610..5f3958f35bde7d43493b2eaff9ee2c5464f30a58 100644 (file)
@@ -18,7 +18,7 @@
 }
 
 .navbar-context-meta-branch {
-  margin-top: 20px;
+  margin-top: 3px;
   line-height: 16px;
 }
 
index 93961a705489cae09d4f22db9246c24a473810d6..c59cebdd6f8eb1b94ca504a57ee085116698dff7 100644 (file)
@@ -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">
index ece4360a4dc266d2b043f6eb870a0a4f300de3e0..40fa2ec46fb8d981d795460e41653d4d4594a778 100644 (file)
@@ -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} />
index af1ef9049844558d14b75e2595aa98e1eca7b14e..69f0fd45640664656257de1f99faafe198e8d1a6 100644 (file)
@@ -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;
     }
 
index ecf5562b8b9641a8ae1f595411acaf222bd9c884..9f8c46a43e8f5a863fda1c033c340e400564436d 100644 (file)
@@ -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>
   );
 }
index 9f3a4e429c8202c7b8cfcdb9a2148249090b8d3f..28931e0fc515a75d8070aa307c9618ac58928f09 100644 (file)
@@ -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();
+});
index 0c50f2de673a58114bc49ed14aef73c510fa0632..ad86f8f2246e0bb7d3acfcd4994c6eabcd7d5c47 100644 (file)
@@ -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()
+  );
 });
index c1aed6ae1b687875aad9310a92f13fdd69caee61..f4edb48406f4a7accec3edbc552fa09875c58774 100644 (file)
@@ -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"
index bad199992da86d370641e58265bde232a8212143..1cb875eee66b76c05300a729006e5ce5c90ba606 100644 (file)
@@ -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>
index 97421e0df875099f50b960af83c71acdd81535dd..9639b62f57f3e3c54eea271f2ca9aed77caed84c 100644 (file)
@@ -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>
 `;
index b8bba666f102774b8ba88bebd2f2c6fec7a85dad..0cc92e8008e25f92d0fa1eaf80b1a66c50d1246a 100644 (file)
@@ -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} />
index f31097d6911704b01e7049659c73fabf2babbf6d..ea135765ece302b5182d7c2b563a13666df5fab2 100644 (file)
@@ -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"
index 2e53e8c87ab253835b3bac56bbf32a25b56f3de9..4f466e19461940cc991fdb42fdd27bac93d04e4d 100644 (file)
@@ -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">
index 655f063d4c7ca020dc0feaa600c07c6e606cf5e4..78a96970467d99d051ae78e34ad24646869578c3 100644 (file)
@@ -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