1
0
mirror of https://github.com/ascribe/onion.git synced 2025-01-03 10:25:08 +01:00
onion/js/components/nav_routes_links.js
Brett Sun f9dcdb0318 Control expanded state of Navbar.Collapse
Controlling the expanded state allows us to close the collapse after
items are selected (as recommended by react-bootstrap maintainers).

Also makes changes to the nav components to pass through props
(required by react-bootstrap to correctly wire everything together).
2016-06-17 16:32:37 +02:00

122 lines
4.0 KiB
JavaScript

import React from 'react';
import Nav from 'react-bootstrap/lib/Nav';
import AclProxy from './acl_proxy';
import NavRoutesLinksLink from './nav_routes_links_link';
import { sanitizeList } from '../utils/general';
const DISABLE_ENUM = ['hasPieces', 'noPieces'];
const NavRoutesLinks = React.createClass({
propTypes: {
hasPieces: React.PropTypes.bool,
routes: React.PropTypes.arrayOf(React.PropTypes.object),
userAcl: React.PropTypes.object
// All other props are passed to the backing Nav
},
isRouteDisabled(disableOn) {
const { hasPieces } = this.props;
if (disableOn && !DISABLE_ENUM.includes(disableOn)) {
throw new Error(
`"disableOn" must be one of: [${DISABLE_ENUM.join(', ')}] got "${disableOn}" instead`
);
}
if (disableOn === 'hasPieces') {
return hasPieces;
} else if (disableOn === 'noPieces') {
return !hasPieces;
} else {
return false;
}
},
/**
* This method generates a bunch of react-bootstrap specific links
* from the routes we defined in one of the specific routes.js file
*
* We can define a headerTitle as well as a aclName and according to that the
* link will be created for a specific user
* @param {ReactElement} node Starts at the very top of a routes files root
* @param {object} userAcl ACL object we use throughout the whole app
* @param {number} i Depth of the route in comparison to the root
* @return {Array} Array of ReactElements that can be displayed to the user
*/
extractLinksFromRoutes(node, userAcl, i) {
if (!node) {
return null;
}
const links = node.childRoutes.map((child, j) => {
const { aclName, disableOn, headerTitle, path } = child;
// We validate if the user has set the title correctly,
// otherwise we're not going to render his route
if (headerTitle && typeof headerTitle === 'string') {
let nestedChildren = null;
// If the node has children that could be rendered, then we want
// to execute this function again with the child as the root
//
// Otherwise we'll just pass nestedChildren as false
if (child.childRoutes && child.childRoutes.length) {
nestedChildren = this.extractLinksFromRoutes(child, userAcl, i++);
}
const navLinkProps = {
headerTitle,
children: nestedChildren,
depth: i,
disabled: this.isRouteDisabled(disableOn),
routePath: `/${path}`
};
// if there is an aclName present on the route definition,
// we evaluate it against the user's acl
if (aclName && typeof aclName !== 'undefined') {
return (
<AclProxy
key={j}
aclName={aclName}
aclObject={this.props.userAcl}>
<NavRoutesLinksLink {...navLinkProps} />
</AclProxy>
);
} else {
return (
<NavRoutesLinksLink key={j} {...navLinkProps} />
);
}
} else {
return null;
}
});
// remove all nulls from the list of generated links
return sanitizeList(links);
},
render() {
const {
routes,
userAcl,
hasPieces: ignoredHasPieces,
...props
} = this.props;
return (
<Nav {...props}>
{this.extractLinksFromRoutes(routes[0], userAcl, 0)}
</Nav>
);
}
});
export default NavRoutesLinks;