Render Admin NavBlock based on authorization

Require location prop as propType in SideNav to prevent silent fail.
Add guard clause on isUsingAuth to prevent DOM break in Authorized.
Consolidate return on Authorized render.
Clean up Authorized.

Signed-off-by: Alex Paxton <thealexpaxton@gmail.com>
pull/10616/head
Jared Scheib 2017-10-25 16:22:00 -07:00 committed by Alex Paxton
parent c8163b68aa
commit 95917837e3
3 changed files with 30 additions and 16 deletions

View File

@ -33,19 +33,28 @@ export const isUserAuthorized = (meRole, requiredRole) => {
const getRoleName = ({roles: [{name}, ..._]}) => name
const Authorized = ({children, me, isUsingAuth, requiredRole, replaceWith}) => {
if (!isUsingAuth) {
return React.isValidElement(children) ? children : children[0]
const Authorized = ({
children,
me,
isUsingAuth,
requiredRole,
replaceWith,
...additionalProps
}) => {
// if me response has not been received yet, render nothing
if (typeof isUsingAuth !== 'boolean') {
return null
}
const meRole = getRoleName(me)
if (isUserAuthorized(meRole, requiredRole)) {
if (!isUsingAuth || isUserAuthorized(meRole, requiredRole)) {
return React.cloneElement(
React.isValidElement(children) ? children : children[0]
)
React.isValidElement(children) ? children : children[0],
{...additionalProps}
) // guards against multiple children wrapped by Authorized
}
return replaceWith ? React.cloneElement(replaceWith) : null
return replaceWith ? replaceWith : null
// if you want elements to be disabled instead of hidden:
// return React.cloneElement(clonedElement, {disabled: !isAuthorized})
@ -54,7 +63,7 @@ const Authorized = ({children, me, isUsingAuth, requiredRole, replaceWith}) => {
const {arrayOf, bool, node, shape, string} = PropTypes
Authorized.propTypes = {
isUsingAuth: bool.isRequired,
isUsingAuth: bool,
replaceWith: node,
children: node.isRequired,
me: shape({

View File

@ -2,13 +2,15 @@ import React, {PropTypes} from 'react'
import {Link} from 'react-router'
import classnames from 'classnames'
import Authorized from 'src/auth/Authorized'
const {bool, node, string} = PropTypes
const NavListItem = React.createClass({
propTypes: {
link: string.isRequired,
children: node,
location: string,
location: string.isRequired,
useAnchor: bool,
isExternal: bool,
},
@ -60,15 +62,14 @@ const NavBlock = React.createClass({
children: node,
link: string,
icon: string.isRequired,
location: string,
location: string.isRequired,
className: string,
},
render() {
const {location, className} = this.props
const isActive = React.Children.toArray(this.props.children).find(child => {
return location.startsWith(child.props.link)
return location.startsWith(child.props.link) // if location is undefined, this will fail silently
})
const children = React.Children.map(this.props.children, child => {
@ -119,7 +120,7 @@ const NavBar = React.createClass({
render() {
const children = React.Children.map(this.props.children, child => {
if (child && child.type === NavBlock) {
if (child && (child.type === NavBlock || child.type === Authorized)) {
return React.cloneElement(child, {
location: this.props.location,
})

View File

@ -2,6 +2,8 @@ import React, {PropTypes} from 'react'
import {withRouter, Link} from 'react-router'
import {connect} from 'react-redux'
import Authorized, {ADMIN_ROLE} from 'src/auth/Authorized'
import {
NavBar,
NavBlock,
@ -108,9 +110,11 @@ const SideNav = React.createClass({
Create
</NavListItem>
</NavBlock>
<NavBlock icon="crown2" link={`${sourcePrefix}/admin`}>
<NavHeader link={`${sourcePrefix}/admin`} title="Admin" />
</NavBlock>
<Authorized requiredRole={ADMIN_ROLE}>
<NavBlock icon="crown2" link={`${sourcePrefix}/admin`}>
<NavHeader link={`${sourcePrefix}/admin`} title="Admin" />
</NavBlock>
</Authorized>
<NavBlock icon="cog-thick" link={`${sourcePrefix}/manage-sources`}>
<NavHeader
link={`${sourcePrefix}/manage-sources`}