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
parent
c8163b68aa
commit
95917837e3
|
@ -33,19 +33,28 @@ export const isUserAuthorized = (meRole, requiredRole) => {
|
||||||
|
|
||||||
const getRoleName = ({roles: [{name}, ..._]}) => name
|
const getRoleName = ({roles: [{name}, ..._]}) => name
|
||||||
|
|
||||||
const Authorized = ({children, me, isUsingAuth, requiredRole, replaceWith}) => {
|
const Authorized = ({
|
||||||
if (!isUsingAuth) {
|
children,
|
||||||
return React.isValidElement(children) ? children : children[0]
|
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)
|
const meRole = getRoleName(me)
|
||||||
if (isUserAuthorized(meRole, requiredRole)) {
|
if (!isUsingAuth || isUserAuthorized(meRole, requiredRole)) {
|
||||||
return React.cloneElement(
|
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:
|
// if you want elements to be disabled instead of hidden:
|
||||||
// return React.cloneElement(clonedElement, {disabled: !isAuthorized})
|
// return React.cloneElement(clonedElement, {disabled: !isAuthorized})
|
||||||
|
@ -54,7 +63,7 @@ const Authorized = ({children, me, isUsingAuth, requiredRole, replaceWith}) => {
|
||||||
const {arrayOf, bool, node, shape, string} = PropTypes
|
const {arrayOf, bool, node, shape, string} = PropTypes
|
||||||
|
|
||||||
Authorized.propTypes = {
|
Authorized.propTypes = {
|
||||||
isUsingAuth: bool.isRequired,
|
isUsingAuth: bool,
|
||||||
replaceWith: node,
|
replaceWith: node,
|
||||||
children: node.isRequired,
|
children: node.isRequired,
|
||||||
me: shape({
|
me: shape({
|
||||||
|
|
|
@ -2,13 +2,15 @@ import React, {PropTypes} from 'react'
|
||||||
import {Link} from 'react-router'
|
import {Link} from 'react-router'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
|
||||||
|
import Authorized from 'src/auth/Authorized'
|
||||||
|
|
||||||
const {bool, node, string} = PropTypes
|
const {bool, node, string} = PropTypes
|
||||||
|
|
||||||
const NavListItem = React.createClass({
|
const NavListItem = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
link: string.isRequired,
|
link: string.isRequired,
|
||||||
children: node,
|
children: node,
|
||||||
location: string,
|
location: string.isRequired,
|
||||||
useAnchor: bool,
|
useAnchor: bool,
|
||||||
isExternal: bool,
|
isExternal: bool,
|
||||||
},
|
},
|
||||||
|
@ -60,15 +62,14 @@ const NavBlock = React.createClass({
|
||||||
children: node,
|
children: node,
|
||||||
link: string,
|
link: string,
|
||||||
icon: string.isRequired,
|
icon: string.isRequired,
|
||||||
location: string,
|
location: string.isRequired,
|
||||||
className: string,
|
className: string,
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {location, className} = this.props
|
const {location, className} = this.props
|
||||||
|
|
||||||
const isActive = React.Children.toArray(this.props.children).find(child => {
|
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 => {
|
const children = React.Children.map(this.props.children, child => {
|
||||||
|
@ -119,7 +120,7 @@ const NavBar = React.createClass({
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const children = React.Children.map(this.props.children, child => {
|
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, {
|
return React.cloneElement(child, {
|
||||||
location: this.props.location,
|
location: this.props.location,
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,6 +2,8 @@ import React, {PropTypes} from 'react'
|
||||||
import {withRouter, Link} from 'react-router'
|
import {withRouter, Link} from 'react-router'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
|
|
||||||
|
import Authorized, {ADMIN_ROLE} from 'src/auth/Authorized'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NavBar,
|
NavBar,
|
||||||
NavBlock,
|
NavBlock,
|
||||||
|
@ -108,9 +110,11 @@ const SideNav = React.createClass({
|
||||||
Create
|
Create
|
||||||
</NavListItem>
|
</NavListItem>
|
||||||
</NavBlock>
|
</NavBlock>
|
||||||
<NavBlock icon="crown2" link={`${sourcePrefix}/admin`}>
|
<Authorized requiredRole={ADMIN_ROLE}>
|
||||||
<NavHeader link={`${sourcePrefix}/admin`} title="Admin" />
|
<NavBlock icon="crown2" link={`${sourcePrefix}/admin`}>
|
||||||
</NavBlock>
|
<NavHeader link={`${sourcePrefix}/admin`} title="Admin" />
|
||||||
|
</NavBlock>
|
||||||
|
</Authorized>
|
||||||
<NavBlock icon="cog-thick" link={`${sourcePrefix}/manage-sources`}>
|
<NavBlock icon="cog-thick" link={`${sourcePrefix}/manage-sources`}>
|
||||||
<NavHeader
|
<NavHeader
|
||||||
link={`${sourcePrefix}/manage-sources`}
|
link={`${sourcePrefix}/manage-sources`}
|
||||||
|
|
Loading…
Reference in New Issue