]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8627 Display organization on the project dashboard
authorStas Vilchik <vilchiks@gmail.com>
Wed, 18 Jan 2017 09:38:13 +0000 (10:38 +0100)
committerStas Vilchik <stas-vilchik@users.noreply.github.com>
Tue, 24 Jan 2017 08:25:53 +0000 (09:25 +0100)
server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css
server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.js
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.js
server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.js
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.js.snap [new file with mode: 0644]
server/sonar-web/src/main/js/store/rootActions.js
server/sonar-web/src/main/less/components/navbar.less
server/sonar-web/src/main/less/components/ui.less

index 59d210c9534584e2dd83d913c1aa08ed81b02aa4..db1b0b701067a9ec97b913f7728b9da7399f12e8 100644 (file)
@@ -4,6 +4,12 @@
   height: 65px;
 }
 
+.navbar-context .navbar-nav > li > span {
+  display: inline-block;
+  padding: 3px 10px;
+  line-height: 20px;
+}
+
 .navbar-context-inner {
   position: fixed;
   z-index: 420;
index 73ceb41f44643dd34ba722fdcb9d876910d31300..cbaa9fb25202c5023fe8b2f635a2992cc40dc6b8 100644 (file)
@@ -70,6 +70,7 @@ export default React.createClass({
                   favorite={this.props.component.isFavorite}/>
 
               <ComponentNavBreadcrumbs
+                  component={this.props.component}
                   breadcrumbs={this.props.component.breadcrumbs}/>
 
               <TooltipsContainer options={{ delay: { show: 0, hide: 2000 } }}>
index 248d96d7258f3c55daf39d86eb17a53988a287ec..dddd47dde40ebe8626adea127eda93f345f274ca 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import React from 'react';
+import { connect } from 'react-redux';
+import { Link } from 'react-router';
 import QualifierIcon from '../../../../components/shared/qualifier-icon';
+import { getOrganizationByKey, areThereCustomOrganizations } from '../../../../store/rootReducer';
 
-export default class ComponentNavBreadcrumbs extends React.Component {
+class ComponentNavBreadcrumbs extends React.Component {
   static propTypes = {
     breadcrumbs: React.PropTypes.array
   };
 
   render () {
-    if (!this.props.breadcrumbs) {
+    const { breadcrumbs, organization, shouldOrganizationBeDisplayed } = this.props;
+
+    if (!breadcrumbs) {
       return null;
     }
 
-    const items = this.props.breadcrumbs.map((item, index) => {
-      const url = `${window.baseUrl}/dashboard/index?id=${encodeURIComponent(item.key)}`;
+    const items = breadcrumbs.map(item => {
       return (
-          <li key={index}>
-            <a href={url}>
-              <QualifierIcon qualifier={item.qualifier}/>&nbsp;{item.name}
-            </a>
+          <li key={item.key}>
+            <Link to={{ pathname: '/dashboard', query: { id: item.key } }}>
+              <QualifierIcon qualifier={item.qualifier}/>
+              {' '}
+              {item.name}
+            </Link>
           </li>
       );
     });
 
     return (
-        <ul className="nav navbar-nav nav-crumbs">{items}</ul>
+        <ul className="nav navbar-nav nav-crumbs">
+          {organization != null && shouldOrganizationBeDisplayed && (
+              <li>
+                <span>{organization.name}</span>
+              </li>
+          )}
+          {items}
+        </ul>
     );
   }
 }
+
+const mapStateToProps = (state, ownProps) => ({
+  organization: ownProps.component.organization && getOrganizationByKey(state, ownProps.component.organization),
+  shouldOrganizationBeDisplayed: areThereCustomOrganizations(state)
+});
+
+export default connect(mapStateToProps)(ComponentNavBreadcrumbs);
+
+export const Unconnected = ComponentNavBreadcrumbs;
index 00683ab73e00e6b7ac5418628550a594ae796892..1f21c41d0de6e1c6cee267bafa5842a7a3693318 100644 (file)
  */
 import React from 'react';
 import { shallow } from 'enzyme';
-import ComponentNavBreadcrumbs from '../ComponentNavBreadcrumbs';
+import { Unconnected } from '../ComponentNavBreadcrumbs';
 
 it('should not render breadcrumbs with one element', () => {
   const breadcrumbs = [{ key: 'my-project', name: 'My Project', qualifier: 'TRK' }];
-  const result = shallow(<ComponentNavBreadcrumbs breadcrumbs={breadcrumbs}/>);
-  expect(result.find('li').length).toBe(1);
-  expect(result.find('a').length).toBe(1);
+  const result = shallow(<Unconnected breadcrumbs={breadcrumbs}/>);
+  expect(result).toMatchSnapshot();
+});
+
+it('should render organization', () => {
+  const breadcrumbs = [{ key: 'my-project', name: 'My Project', qualifier: 'TRK' }];
+  const organization = { key: 'foo', name: 'The Foo Organization' };
+  const result = shallow(
+      <Unconnected
+          breadcrumbs={breadcrumbs}
+          organization={organization}
+          shouldOrganizationBeDisplayed={true}/>);
+  expect(result).toMatchSnapshot();
 });
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.js.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.js.snap
new file mode 100644 (file)
index 0000000..b3b3e10
--- /dev/null
@@ -0,0 +1,52 @@
+exports[`test should not render breadcrumbs with one element 1`] = `
+<ul
+  className="nav navbar-nav nav-crumbs">
+  <li>
+    <Link
+      onlyActiveOnIndex={false}
+      style={Object {}}
+      to={
+        Object {
+          "pathname": "/dashboard",
+          "query": Object {
+            "id": "my-project",
+          },
+        }
+      }>
+      <qualifier-icon
+        qualifier="TRK" />
+       
+      My Project
+    </Link>
+  </li>
+</ul>
+`;
+
+exports[`test should render organization 1`] = `
+<ul
+  className="nav navbar-nav nav-crumbs">
+  <li>
+    <span>
+      The Foo Organization
+    </span>
+  </li>
+  <li>
+    <Link
+      onlyActiveOnIndex={false}
+      style={Object {}}
+      to={
+        Object {
+          "pathname": "/dashboard",
+          "query": Object {
+            "id": "my-project",
+          },
+        }
+      }>
+      <qualifier-icon
+        qualifier="TRK" />
+       
+      My Project
+    </Link>
+  </li>
+</ul>
+`;
index 00ff39711851686bda433b2e9d22317a4f5d1c8e..f0193e16a7ad0b0002e55efee4ab228d72f1f590 100644 (file)
@@ -46,8 +46,8 @@ export const fetchLanguages = () => dispatch => {
   );
 };
 
-export const fetchOrganizations = () => dispatch => (
-    getOrganizations().then(
+export const fetchOrganizations = (organizations?: Array<string>) => dispatch => (
+    getOrganizations(organizations).then(
         r => dispatch(receiveOrganizations(r.organizations)),
         onFail(dispatch)
     )
@@ -60,7 +60,12 @@ const addQualifier = project => ({
 
 export const fetchProject = key => dispatch => (
     getComponentNavigation(key).then(
-        component => dispatch(receiveComponents([addQualifier(component)])),
+        component => {
+          dispatch(receiveComponents([addQualifier(component)]));
+          if (component.organization != null) {
+            dispatch(fetchOrganizations([component.organization]));
+          }
+        },
         onFail(dispatch)
     )
 );
index 7d2c9a712bb4c53b6f6d7e41ffe902dc6d44a8d5..7a14845b96a31e4e0ba1437e867c7ed653e41bb5 100644 (file)
 
 .navbar-context-favorite {
   float: left;
-  padding: 6px 0 0 10px;
+  padding: 7px 0 0 10px;
 }
 
 .navbar-context-meta {
index 1a749540cab9744b26cef0d9462fd66cd84d01ca..d15bf32db51ff806663295786c6a5e64f263ac5e 100644 (file)
     }
   }
 
+  > li {
+    font-size: 16px;
+    font-weight: 400;
+  }
+
   > li + li:before {
     content: "/";
     float: left;
     color: fade(@baseFontColor, 30%);
   }
 
-  > li:first-child {
-    font-size: 18px;
-    font-weight: 400;
-
-    > a {
-      color: @baseFontColor;
-    }
-  }
-
   [class^="icon-"], [class*=" icon-"] {
     position: relative;
     top: 2px;