@@ -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; |
@@ -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 } }}> |
@@ -18,31 +18,53 @@ | |||
* 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}/> {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; |
@@ -19,11 +19,21 @@ | |||
*/ | |||
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(); | |||
}); |
@@ -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> | |||
`; |
@@ -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) | |||
) | |||
); |
@@ -230,7 +230,7 @@ | |||
.navbar-context-favorite { | |||
float: left; | |||
padding: 6px 0 0 10px; | |||
padding: 7px 0 0 10px; | |||
} | |||
.navbar-context-meta { |
@@ -139,6 +139,11 @@ | |||
} | |||
} | |||
> li { | |||
font-size: 16px; | |||
font-weight: 400; | |||
} | |||
> li + li:before { | |||
content: "/"; | |||
float: left; | |||
@@ -146,15 +151,6 @@ | |||
color: fade(@baseFontColor, 30%); | |||
} | |||
> li:first-child { | |||
font-size: 18px; | |||
font-weight: 400; | |||
> a { | |||
color: @baseFontColor; | |||
} | |||
} | |||
[class^="icon-"], [class*=" icon-"] { | |||
position: relative; | |||
top: 2px; |