From 34a91334ebac1e8c7c870d1372d6c29c8fb6adaf Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Mon, 23 Oct 2017 17:43:21 -0700 Subject: [PATCH 01/43] Add 'Authorized' HOC to hide components based on me Role Signed-off-by: Alex Paxton --- ui/src/auth/Authorized.js | 72 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 ui/src/auth/Authorized.js diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js new file mode 100644 index 0000000000..2d1180754f --- /dev/null +++ b/ui/src/auth/Authorized.js @@ -0,0 +1,72 @@ +import React, {Component, PropTypes} from 'react' + +import {connect} from 'react-redux' + +const VIEWER_ROLE = 'viewer' +const EDITOR_ROLE = 'editor' +const ADMIN_ROLE = 'admin' +const SUPERADMIN_ROLE = 'superadmin' + +const getRoleName = ({roles: [{name}, ..._]}) => name + +class Authorized extends Component { + isAuthorized = (meRole, requiredRole) => { + switch (requiredRole) { + case VIEWER_ROLE: + return ( + meRole === VIEWER_ROLE || + meRole === EDITOR_ROLE || + meRole === ADMIN_ROLE || + meRole === SUPERADMIN_ROLE + ) + case EDITOR_ROLE: + return ( + meRole === EDITOR_ROLE || + meRole === ADMIN_ROLE || + meRole === SUPERADMIN_ROLE + ) + case ADMIN_ROLE: + return meRole === ADMIN_ROLE || meRole === SUPERADMIN_ROLE + case SUPERADMIN_ROLE: + return meRole === SUPERADMIN_ROLE + default: + return false + } + } + + render() { + // TODO: make this return component if not using auth + const {children, me, requiredRole} = this.props + + const meRole = getRoleName(me) + + return this.isAuthorized(meRole, requiredRole) + ? React.cloneElement( + React.isValidElement(children) ? children : children[0] + ) + : null + + // if you want elements to be disabled instead of hidden: + // return React.cloneElement(clonedElement, {disabled: !isAuthorized}) + } +} + +const {arrayOf, node, shape, string} = PropTypes + +Authorized.propTypes = { + children: node.isRequired, + me: shape({ + roles: arrayOf( + shape({ + name: string.isRequired, + }) + ), + }), + requiredRole: string.isRequired, +} + +const mapStateToProps = ({auth: {me}}) => ({ + me, +}) + +export default connect(mapStateToProps)(Authorized) From e7721166d9c51e7e17663316df989939e28a946e Mon Sep 17 00:00:00 2001 From: Alex Paxton Date: Mon, 23 Oct 2017 17:50:43 -0700 Subject: [PATCH 02/43] Implement Authorized HOC on DashboardsPage Signed-off-by: Jared Scheib --- .../components/DashboardsPageContents.js | 18 ++++++++++++------ .../dashboards/components/DashboardsTable.js | 14 +++++++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/ui/src/dashboards/components/DashboardsPageContents.js b/ui/src/dashboards/components/DashboardsPageContents.js index 987a75ae43..608fd90c98 100644 --- a/ui/src/dashboards/components/DashboardsPageContents.js +++ b/ui/src/dashboards/components/DashboardsPageContents.js @@ -3,6 +3,8 @@ import React, {PropTypes} from 'react' import DashboardsTable from 'src/dashboards/components/DashboardsTable' import FancyScrollbar from 'shared/components/FancyScrollbar' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + const DashboardsPageContents = ({ dashboards, onDeleteDashboard, @@ -28,12 +30,16 @@ const DashboardsPageContents = ({

{tableHeader}

- + { + + + + }
None} - + + + )} From 40de9eb1c5d9951b5185bee90b5986e4f43a14c3 Mon Sep 17 00:00:00 2001 From: Alex Paxton Date: Mon, 23 Oct 2017 17:53:33 -0700 Subject: [PATCH 03/43] FOR TESTING - DELETE THIS COMMIT: User Role = Viewer Signed-off-by: Jared Scheib --- bolt/users.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bolt/users.go b/bolt/users.go index feadb60c39..012588caaa 100644 --- a/bolt/users.go +++ b/bolt/users.go @@ -76,6 +76,12 @@ func (s *UsersStore) Get(ctx context.Context, q chronograf.UserQuery) (*chronogr return nil, chronograf.ErrUserNotFound } + user.Roles = []chronograf.Role{ + { + Name: "viewer", + }, + } + return user, nil } From 8cc9167448ddfb2051c28583883d68345b35265b Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 24 Oct 2017 13:30:51 -0700 Subject: [PATCH 04/43] Fix typo in prop --- ui/src/dashboards/components/DashboardsTable.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/dashboards/components/DashboardsTable.js b/ui/src/dashboards/components/DashboardsTable.js index fd884eccf0..6496ce9e6d 100644 --- a/ui/src/dashboards/components/DashboardsTable.js +++ b/ui/src/dashboards/components/DashboardsTable.js @@ -38,7 +38,7 @@ const DashboardsTable = ({ ) : None} - + Date: Tue, 24 Oct 2017 17:04:06 -0700 Subject: [PATCH 05/43] Export role name consts in client to fix Authorized HOC Signed-off-by: Alex Paxton --- ui/src/auth/Authorized.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index 2d1180754f..8b1baebd02 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -2,10 +2,10 @@ import React, {Component, PropTypes} from 'react' import {connect} from 'react-redux' -const VIEWER_ROLE = 'viewer' -const EDITOR_ROLE = 'editor' -const ADMIN_ROLE = 'admin' -const SUPERADMIN_ROLE = 'superadmin' +export const VIEWER_ROLE = 'viewer' +export const EDITOR_ROLE = 'editor' +export const ADMIN_ROLE = 'admin' +export const SUPERADMIN_ROLE = 'superadmin' const getRoleName = ({roles: [{name}, ..._]}) => name From a9c83ed3cde590acf4b84acdd73cf8bb2c1c37a2 Mon Sep 17 00:00:00 2001 From: Alex Paxton Date: Tue, 24 Oct 2017 17:16:11 -0700 Subject: [PATCH 06/43] Add param to Authorized to replace unauthorized component with node Signed-off-by: Jared Scheib --- ui/src/auth/Authorized.js | 14 ++++++++------ ui/src/dashboards/components/DashboardsTable.js | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index 8b1baebd02..d8123ab3a9 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -36,15 +36,16 @@ class Authorized extends Component { render() { // TODO: make this return component if not using auth - const {children, me, requiredRole} = this.props + const {children, me, requiredRole, replaceWith} = this.props const meRole = getRoleName(me) - return this.isAuthorized(meRole, requiredRole) - ? React.cloneElement( - React.isValidElement(children) ? children : children[0] - ) - : null + if (this.isAuthorized(meRole, requiredRole)) { + return React.cloneElement( + React.isValidElement(children) ? children : children[0] + ) + } + return replaceWith ? React.cloneElement(replaceWith) : null // if you want elements to be disabled instead of hidden: // return React.cloneElement(clonedElement, {disabled: !isAuthorized}) @@ -54,6 +55,7 @@ class Authorized extends Component { const {arrayOf, node, shape, string} = PropTypes Authorized.propTypes = { + replaceWith: node, children: node.isRequired, me: shape({ roles: arrayOf( diff --git a/ui/src/dashboards/components/DashboardsTable.js b/ui/src/dashboards/components/DashboardsTable.js index 6496ce9e6d..9f688ad47d 100644 --- a/ui/src/dashboards/components/DashboardsTable.js +++ b/ui/src/dashboards/components/DashboardsTable.js @@ -38,7 +38,7 @@ const DashboardsTable = ({ ) : None} - + }> Date: Tue, 24 Oct 2017 17:43:16 -0700 Subject: [PATCH 07/43] Render original component in Authorized if not using auth Make isUsingAuth a app-wide Redux key. Refactor its usage in SideNav, and use it in Authorized. Signed-off-by: Alex Paxton --- ui/src/auth/Authorized.js | 15 ++++++++++----- ui/src/shared/reducers/auth.js | 2 +- ui/src/side_nav/containers/SideNav.js | 6 ++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index d8123ab3a9..f4fb8ceb1d 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -35,16 +35,19 @@ class Authorized extends Component { } render() { - // TODO: make this return component if not using auth - const {children, me, requiredRole, replaceWith} = this.props + const {children, me, isUsingAuth, requiredRole, replaceWith} = this.props + + if (!isUsingAuth) { + return React.isValidElement(children) ? children : children[0] + } const meRole = getRoleName(me) - if (this.isAuthorized(meRole, requiredRole)) { return React.cloneElement( React.isValidElement(children) ? children : children[0] ) } + return replaceWith ? React.cloneElement(replaceWith) : null // if you want elements to be disabled instead of hidden: @@ -52,9 +55,10 @@ class Authorized extends Component { } } -const {arrayOf, node, shape, string} = PropTypes +const {arrayOf, bool, node, shape, string} = PropTypes Authorized.propTypes = { + isUsingAuth: bool.isRequired, replaceWith: node, children: node.isRequired, me: shape({ @@ -67,8 +71,9 @@ Authorized.propTypes = { requiredRole: string.isRequired, } -const mapStateToProps = ({auth: {me}}) => ({ +const mapStateToProps = ({auth: {me, isUsingAuth}}) => ({ me, + isUsingAuth, }) export default connect(mapStateToProps)(Authorized) diff --git a/ui/src/shared/reducers/auth.js b/ui/src/shared/reducers/auth.js index 889f1887fb..09f406da61 100644 --- a/ui/src/shared/reducers/auth.js +++ b/ui/src/shared/reducers/auth.js @@ -30,7 +30,7 @@ const authReducer = (state = initialState, action) => { } case 'LOGOUT_LINK_RECEIVED': { const {logoutLink} = action.payload - return {...state, logoutLink} + return {...state, logoutLink, isUsingAuth: !!logoutLink} } } diff --git a/ui/src/side_nav/containers/SideNav.js b/ui/src/side_nav/containers/SideNav.js index a15293b46b..113b4727f3 100644 --- a/ui/src/side_nav/containers/SideNav.js +++ b/ui/src/side_nav/containers/SideNav.js @@ -22,6 +22,7 @@ const SideNav = React.createClass({ pathname: string.isRequired, }).isRequired, isHidden: bool.isRequired, + isUsingAuth: bool, logoutLink: string, customLinks: arrayOf( shape({ @@ -61,13 +62,13 @@ const SideNav = React.createClass({ params: {sourceID}, location: {pathname: location}, isHidden, + isUsingAuth, logoutLink, customLinks, } = this.props const sourcePrefix = `/sources/${sourceID}` const dataExplorerLink = `${sourcePrefix}/chronograf/data-explorer` - const isUsingAuth = !!logoutLink const isDefaultPage = location.split('/').includes(DEFAULT_HOME_PAGE) @@ -135,11 +136,12 @@ const SideNav = React.createClass({ }) const mapStateToProps = ({ - auth: {logoutLink}, + auth: {isUsingAuth, logoutLink}, app: {ephemeral: {inPresentationMode}}, links: {external: {custom: customLinks}}, }) => ({ isHidden: inPresentationMode, + isUsingAuth, logoutLink, customLinks, }) From 2927d1e1e86976057638ee52916942279724c03f Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Tue, 24 Oct 2017 17:48:41 -0700 Subject: [PATCH 08/43] Cleanup Signed-off-by: Alex Paxton --- .../components/DashboardsPageContents.js | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/ui/src/dashboards/components/DashboardsPageContents.js b/ui/src/dashboards/components/DashboardsPageContents.js index 608fd90c98..88fac75514 100644 --- a/ui/src/dashboards/components/DashboardsPageContents.js +++ b/ui/src/dashboards/components/DashboardsPageContents.js @@ -1,10 +1,10 @@ import React, {PropTypes} from 'react' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + import DashboardsTable from 'src/dashboards/components/DashboardsTable' import FancyScrollbar from 'shared/components/FancyScrollbar' -import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' - const DashboardsPageContents = ({ dashboards, onDeleteDashboard, @@ -30,16 +30,14 @@ const DashboardsPageContents = ({

{tableHeader}

- { - - - - } + + +
Date: Tue, 24 Oct 2017 17:51:38 -0700 Subject: [PATCH 09/43] Wrap 'Add Cell' with Authorized HOC Signed-off-by: Jared Scheib --- ui/src/dashboards/components/DashboardHeader.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ui/src/dashboards/components/DashboardHeader.js b/ui/src/dashboards/components/DashboardHeader.js index ff670787fd..e4ac27e707 100644 --- a/ui/src/dashboards/components/DashboardHeader.js +++ b/ui/src/dashboards/components/DashboardHeader.js @@ -1,6 +1,8 @@ import React, {PropTypes} from 'react' import classnames from 'classnames' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown' import TimeRangeDropdown from 'shared/components/TimeRangeDropdown' import SourceIndicator from 'shared/components/SourceIndicator' @@ -50,10 +52,15 @@ const DashboardHeader = ({ {dashboard - ? + ? + + : null} {dashboard ?
} - + + + From 7feaa1ddcd93cb0f2d8219e5b1efa48a2523d358 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Tue, 24 Oct 2017 18:28:17 -0700 Subject: [PATCH 12/43] Render layout cell menu based on authorization Signed-off-by: Alex Paxton --- ui/src/shared/components/LayoutCell.js | 26 +++++++++++++++----------- ui/src/style/pages/dashboards.scss | 6 ++++-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ui/src/shared/components/LayoutCell.js b/ui/src/shared/components/LayoutCell.js index 3303efd35c..ed240a026b 100644 --- a/ui/src/shared/components/LayoutCell.js +++ b/ui/src/shared/components/LayoutCell.js @@ -1,6 +1,8 @@ import React, {Component, PropTypes} from 'react' import _ from 'lodash' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + import LayoutCellMenu from 'shared/components/LayoutCellMenu' import LayoutCellHeader from 'shared/components/LayoutCellHeader' import {errorThrown} from 'shared/actions/errors' @@ -52,17 +54,19 @@ class LayoutCell extends Component { return (
- + + + Date: Tue, 24 Oct 2017 18:36:32 -0700 Subject: [PATCH 13/43] Export isAuthorized for global use Signed-off-by: Jared Scheib --- ui/src/auth/Authorized.js | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index f4fb8ceb1d..23f5195060 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -7,33 +7,33 @@ export const EDITOR_ROLE = 'editor' export const ADMIN_ROLE = 'admin' export const SUPERADMIN_ROLE = 'superadmin' +export const isUserAuthorized = (meRole, requiredRole) => { + switch (requiredRole) { + case VIEWER_ROLE: + return ( + meRole === VIEWER_ROLE || + meRole === EDITOR_ROLE || + meRole === ADMIN_ROLE || + meRole === SUPERADMIN_ROLE + ) + case EDITOR_ROLE: + return ( + meRole === EDITOR_ROLE || + meRole === ADMIN_ROLE || + meRole === SUPERADMIN_ROLE + ) + case ADMIN_ROLE: + return meRole === ADMIN_ROLE || meRole === SUPERADMIN_ROLE + case SUPERADMIN_ROLE: + return meRole === SUPERADMIN_ROLE + default: + return false + } +} + const getRoleName = ({roles: [{name}, ..._]}) => name class Authorized extends Component { - isAuthorized = (meRole, requiredRole) => { - switch (requiredRole) { - case VIEWER_ROLE: - return ( - meRole === VIEWER_ROLE || - meRole === EDITOR_ROLE || - meRole === ADMIN_ROLE || - meRole === SUPERADMIN_ROLE - ) - case EDITOR_ROLE: - return ( - meRole === EDITOR_ROLE || - meRole === ADMIN_ROLE || - meRole === SUPERADMIN_ROLE - ) - case ADMIN_ROLE: - return meRole === ADMIN_ROLE || meRole === SUPERADMIN_ROLE - case SUPERADMIN_ROLE: - return meRole === SUPERADMIN_ROLE - default: - return false - } - } - render() { const {children, me, isUsingAuth, requiredRole, replaceWith} = this.props @@ -42,7 +42,7 @@ class Authorized extends Component { } const meRole = getRoleName(me) - if (this.isAuthorized(meRole, requiredRole)) { + if (isUserAuthorized(meRole, requiredRole)) { return React.cloneElement( React.isValidElement(children) ? children : children[0] ) From 0b004c949d4ca672ddb6ff7edc1acdbe9a249bd8 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Tue, 24 Oct 2017 18:37:01 -0700 Subject: [PATCH 14/43] Refactor Authorized HOC to SFC Signed-off-by: Alex Paxton --- ui/src/auth/Authorized.js | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index 23f5195060..6a2d2ac283 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -1,4 +1,4 @@ -import React, {Component, PropTypes} from 'react' +import React, {PropTypes} from 'react' import {connect} from 'react-redux' @@ -33,26 +33,22 @@ export const isUserAuthorized = (meRole, requiredRole) => { const getRoleName = ({roles: [{name}, ..._]}) => name -class Authorized extends Component { - render() { - const {children, me, isUsingAuth, requiredRole, replaceWith} = this.props - - if (!isUsingAuth) { - return React.isValidElement(children) ? children : children[0] - } - - const meRole = getRoleName(me) - if (isUserAuthorized(meRole, requiredRole)) { - return React.cloneElement( - React.isValidElement(children) ? children : children[0] - ) - } - - return replaceWith ? React.cloneElement(replaceWith) : null - - // if you want elements to be disabled instead of hidden: - // return React.cloneElement(clonedElement, {disabled: !isAuthorized}) +const Authorized = ({children, me, isUsingAuth, requiredRole, replaceWith}) => { + if (!isUsingAuth) { + return React.isValidElement(children) ? children : children[0] } + + const meRole = getRoleName(me) + if (isUserAuthorized(meRole, requiredRole)) { + return React.cloneElement( + React.isValidElement(children) ? children : children[0] + ) + } + + return replaceWith ? React.cloneElement(replaceWith) : null + + // if you want elements to be disabled instead of hidden: + // return React.cloneElement(clonedElement, {disabled: !isAuthorized}) } const {arrayOf, bool, node, shape, string} = PropTypes From 56ad7dc481f180bedece963635411111b22153be Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 10:29:24 -0700 Subject: [PATCH 15/43] Render Write Data button based on user authorization --- ui/src/data_explorer/containers/Header.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/ui/src/data_explorer/containers/Header.js b/ui/src/data_explorer/containers/Header.js index df57ffb8fa..a5834c2a7b 100644 --- a/ui/src/data_explorer/containers/Header.js +++ b/ui/src/data_explorer/containers/Header.js @@ -1,6 +1,8 @@ import React, {PropTypes} from 'react' import {withRouter} from 'react-router' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown' import TimeRangeDropdown from 'shared/components/TimeRangeDropdown' import SourceIndicator from 'shared/components/SourceIndicator' @@ -24,14 +26,16 @@ const Header = ({
-
- - Write Data -
+ +
+ + Write Data +
+
Date: Wed, 25 Oct 2017 10:33:06 -0700 Subject: [PATCH 16/43] Render Create Rule & Write TICKscript buttons based on user authorization --- ui/src/kapacitor/components/KapacitorRules.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRules.js b/ui/src/kapacitor/components/KapacitorRules.js index d5a7773a16..701cf5ebe4 100644 --- a/ui/src/kapacitor/components/KapacitorRules.js +++ b/ui/src/kapacitor/components/KapacitorRules.js @@ -1,6 +1,8 @@ import React, {PropTypes} from 'react' import {Link} from 'react-router' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + import NoKapacitorError from 'shared/components/NoKapacitorError' import SourceIndicator from 'shared/components/SourceIndicator' import KapacitorRulesTable from 'src/kapacitor/components/KapacitorRulesTable' @@ -20,9 +22,11 @@ const KapacitorRules = ({

Alert Rules

- + + +
@@ -53,15 +57,14 @@ const KapacitorRules = ({

{rHeader}

-
+ Build Rule -
+
{tHeader} -
+ Write TICKscript -
+
Date: Wed, 25 Oct 2017 10:37:33 -0700 Subject: [PATCH 17/43] Render Delete & Edit TICKscript buttons in Rules Table based on user authorization --- .../components/KapacitorRulesTable.js | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.js index 00f6ab2689..66e804fa7c 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.js +++ b/ui/src/kapacitor/components/KapacitorRulesTable.js @@ -2,6 +2,8 @@ import React, {PropTypes} from 'react' import {Link} from 'react-router' import _ from 'lodash' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + import {KAPACITOR_RULES_TABLE} from 'src/kapacitor/constants/tableSizing' const { colName, @@ -77,18 +79,22 @@ const RuleRow = ({rule, source, onDelete, onChangeRuleStatus}) =>
- - Edit TICKscript - - + + + Edit TICKscript + + + + + From 90108188d6733d949d47bfd1324a7d5ffa34f228 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 10:41:04 -0700 Subject: [PATCH 18/43] Render link to Rule Builder based on user authorization --- .../kapacitor/components/KapacitorRulesTable.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.js index 66e804fa7c..e3b352fe25 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.js +++ b/ui/src/kapacitor/components/KapacitorRulesTable.js @@ -109,9 +109,18 @@ const RuleTitle = ({rule: {id, name, query}, source}) => { } return ( - - {name} - + + {name} + + } + > + + {name} + + ) } From 554db6501a1004fc8c4d10b36ed826e8872a24f1 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 12:35:24 -0700 Subject: [PATCH 19/43] Render Edit TICKscript and Delete buttons in TaskTable based on user authorization --- ui/src/kapacitor/components/TasksTable.js | 30 ++++++++++++++--------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/ui/src/kapacitor/components/TasksTable.js b/ui/src/kapacitor/components/TasksTable.js index 75784e508d..e3a09c3127 100644 --- a/ui/src/kapacitor/components/TasksTable.js +++ b/ui/src/kapacitor/components/TasksTable.js @@ -2,6 +2,8 @@ import React, {PropTypes} from 'react' import {Link} from 'react-router' import _ from 'lodash' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + import {TASKS_TABLE} from 'src/kapacitor/constants/tableSizing' const {colID, colType, colEnabled, colActions} = TASKS_TABLE @@ -60,18 +62,22 @@ const TaskRow = ({task, source, onDelete, onChangeRuleStatus}) =>
- - Edit TICKscript - - + + + Edit TICKscript + + + + + From c1b2fdc0810a6fd23be494f620adbbe4f44a94e6 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 13:41:32 -0700 Subject: [PATCH 20/43] Render Add Source, Delete Source, and Edit Source buttons based on user authorization --- ui/src/sources/components/InfluxTable.js | 59 +++++++++++++++--------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/ui/src/sources/components/InfluxTable.js b/ui/src/sources/components/InfluxTable.js index 1887d9dfd5..675ea8e861 100644 --- a/ui/src/sources/components/InfluxTable.js +++ b/ui/src/sources/components/InfluxTable.js @@ -1,6 +1,8 @@ import React, {PropTypes} from 'react' import {Link, withRouter} from 'react-router' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + import Dropdown from 'shared/components/Dropdown' import QuestionMarkTooltip from 'shared/components/QuestionMarkTooltip' @@ -85,12 +87,14 @@ const InfluxTable = ({

InfluxDB Sources

- - Add Source - + + + Add Source + +
@@ -131,28 +135,41 @@ const InfluxTable = ({ From f4a38d83777b9eb804a7bb9d8151e9e2233a57ea Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Thu, 26 Oct 2017 17:54:00 -0700 Subject: [PATCH 31/43] Revert "Render Write Data button based on user authorization" This reverts commit 56ad7dc481f180bedece963635411111b22153be. --- ui/src/data_explorer/containers/Header.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/ui/src/data_explorer/containers/Header.js b/ui/src/data_explorer/containers/Header.js index a5834c2a7b..df57ffb8fa 100644 --- a/ui/src/data_explorer/containers/Header.js +++ b/ui/src/data_explorer/containers/Header.js @@ -1,8 +1,6 @@ import React, {PropTypes} from 'react' import {withRouter} from 'react-router' -import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' - import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown' import TimeRangeDropdown from 'shared/components/TimeRangeDropdown' import SourceIndicator from 'shared/components/SourceIndicator' @@ -26,16 +24,14 @@ const Header = ({
- -
- - Write Data -
-
+
+ + Write Data +
Date: Thu, 26 Oct 2017 17:55:33 -0700 Subject: [PATCH 32/43] Revert "Disable rule Enabled toggle in TaskTable based on user authorization" This reverts commit 15abd3e8005f4fc71a89652bf6d4d698aac28e3d. --- .../kapacitor/components/KapacitorRulesTable.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.js index d63923cdb0..e3b352fe25 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.js +++ b/ui/src/kapacitor/components/KapacitorRulesTable.js @@ -68,15 +68,13 @@ const RuleRow = ({rule, source, onDelete, onChangeRuleStatus}) =>
From 63bfd4e6c939986cd01226e9e8978ab65e187dfe Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Thu, 26 Oct 2017 17:56:34 -0700 Subject: [PATCH 33/43] Revert "Render Edit TICKscript and Delete buttons in TaskTable based on user authorization" This reverts commit 554db6501a1004fc8c4d10b36ed826e8872a24f1. --- ui/src/kapacitor/components/TasksTable.js | 30 +++++++++-------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/ui/src/kapacitor/components/TasksTable.js b/ui/src/kapacitor/components/TasksTable.js index e3a09c3127..75784e508d 100644 --- a/ui/src/kapacitor/components/TasksTable.js +++ b/ui/src/kapacitor/components/TasksTable.js @@ -2,8 +2,6 @@ import React, {PropTypes} from 'react' import {Link} from 'react-router' import _ from 'lodash' -import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' - import {TASKS_TABLE} from 'src/kapacitor/constants/tableSizing' const {colID, colType, colEnabled, colActions} = TASKS_TABLE @@ -62,22 +60,18 @@ const TaskRow = ({task, source, onDelete, onChangeRuleStatus}) => From b67373b9feb8b1481e1f276e71b642cb83bfe88e Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Thu, 26 Oct 2017 17:58:58 -0700 Subject: [PATCH 34/43] Revert "Render Delete & Edit TICKscript buttons in Rules Table based on user authorization" This reverts commit f1d385a97eda4978268502233902c94a9ab5f965. --- .../components/KapacitorRulesTable.js | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.js index e3b352fe25..12cb2858c1 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.js +++ b/ui/src/kapacitor/components/KapacitorRulesTable.js @@ -2,8 +2,6 @@ import React, {PropTypes} from 'react' import {Link} from 'react-router' import _ from 'lodash' -import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' - import {KAPACITOR_RULES_TABLE} from 'src/kapacitor/constants/tableSizing' const { colName, @@ -79,22 +77,18 @@ const RuleRow = ({rule, source, onDelete, onChangeRuleStatus}) => From e29e6aba2ca9df2c8c0c5d00d6bb1886b9a81f19 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Thu, 26 Oct 2017 18:02:26 -0700 Subject: [PATCH 35/43] Revert "Render Create Rule & Write TICKscript buttons based on user authorization" This reverts commit 59a987d22834ac2da74898e8ee29e5f600f1df26. --- ui/src/kapacitor/components/KapacitorRules.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRules.js b/ui/src/kapacitor/components/KapacitorRules.js index 701cf5ebe4..d5a7773a16 100644 --- a/ui/src/kapacitor/components/KapacitorRules.js +++ b/ui/src/kapacitor/components/KapacitorRules.js @@ -1,8 +1,6 @@ import React, {PropTypes} from 'react' import {Link} from 'react-router' -import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' - import NoKapacitorError from 'shared/components/NoKapacitorError' import SourceIndicator from 'shared/components/SourceIndicator' import KapacitorRulesTable from 'src/kapacitor/components/KapacitorRulesTable' @@ -22,11 +20,9 @@ const KapacitorRules = ({

Alert Rules

- - - +
@@ -57,14 +53,15 @@ const KapacitorRules = ({

{rHeader}

- +
Build Rule - +
{tHeader} - +
Write TICKscript - +
Date: Thu, 26 Oct 2017 18:03:45 -0700 Subject: [PATCH 36/43] Revert "Render link to Rule Builder based on user authorization" This reverts commit 90108188d6733d949d47bfd1324a7d5ffa34f228. --- .../kapacitor/components/KapacitorRulesTable.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.js index 12cb2858c1..00f6ab2689 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.js +++ b/ui/src/kapacitor/components/KapacitorRulesTable.js @@ -103,18 +103,9 @@ const RuleTitle = ({rule: {id, name, query}, source}) => { } return ( - - {name} - - } - > - - {name} - - + + {name} + ) } From d4f3f6c7ff65f88e3df49968824f6c65c956ea34 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Thu, 26 Oct 2017 18:13:59 -0700 Subject: [PATCH 37/43] Revert "FOR TESTING - DELETE THIS COMMIT: User Role = Viewer" This reverts commit 40de9eb1c5d9951b5185bee90b5986e4f43a14c3. --- bolt/users.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bolt/users.go b/bolt/users.go index 012588caaa..feadb60c39 100644 --- a/bolt/users.go +++ b/bolt/users.go @@ -76,12 +76,6 @@ func (s *UsersStore) Get(ctx context.Context, q chronograf.UserQuery) (*chronogr return nil, chronograf.ErrUserNotFound } - user.Roles = []chronograf.Role{ - { - Name: "viewer", - }, - } - return user, nil } From 22b53a0199aec2c20b84c59bcf181723050e361e Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 27 Oct 2017 16:42:20 -0700 Subject: [PATCH 38/43] Use lodash to more safely get me role --- ui/src/auth/Authorized.js | 8 ++++++-- ui/src/shared/components/RoleIndicator.js | 6 +++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index ec43cbdb5c..c5abadb5d0 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -1,5 +1,6 @@ import React, {PropTypes} from 'react' import {connect} from 'react-redux' +import _ from 'lodash' export const VIEWER_ROLE = 'viewer' export const EDITOR_ROLE = 'editor' @@ -30,7 +31,9 @@ export const isUserAuthorized = (meRole, requiredRole) => { } } -const getRoleName = ({roles: [{name}, ..._]}) => name +export const getMeRole = me => { + return _.get(_.first(_.get(me, 'roles', [])), 'name', 'none') // TODO: TBD if 'none' should be returned if none +} const Authorized = ({ children, @@ -46,7 +49,8 @@ const Authorized = ({ return null } - const meRole = getRoleName(me) + const meRole = getMeRole(me) + if (!isUsingAuth || isUserAuthorized(meRole, requiredRole)) { return React.cloneElement( React.isValidElement(children) ? children : children[0], diff --git a/ui/src/shared/components/RoleIndicator.js b/ui/src/shared/components/RoleIndicator.js index c425c18c81..2cd5b96a09 100644 --- a/ui/src/shared/components/RoleIndicator.js +++ b/ui/src/shared/components/RoleIndicator.js @@ -1,18 +1,18 @@ import React, {PropTypes} from 'react' import uuid from 'node-uuid' - import {connect} from 'react-redux' import ReactTooltip from 'react-tooltip' -const getRoleName = ({roles: [{name}, ..._]}) => name +import {getMeRole} from 'src/auth/Authorized' const RoleIndicator = ({me, isUsingAuth}) => { if (!isUsingAuth) { return null } - const roleName = getRoleName(me) + const roleName = getMeRole(me) + const RoleTooltip = `

Role: ${roleName}

` const uuidTooltip = uuid.v4() From ee89d49bdb6b70cb2f08d429bb5b740189fcc27b Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 27 Oct 2017 16:42:41 -0700 Subject: [PATCH 39/43] Simplify return logic if replaceWith is undefined --- ui/src/auth/Authorized.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index c5abadb5d0..d27fab7282 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -67,7 +67,7 @@ const Authorized = ({ ) } - return replaceWith ? replaceWith : null + return replaceWith || null // if you want elements to be disabled instead of hidden: // return React.cloneElement(clonedElement, {disabled: !isAuthorized}) From e918c013d31f663afe96aaadd699781a5a0e0a4c Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 27 Oct 2017 16:46:44 -0700 Subject: [PATCH 40/43] Rename source-indicator.scss to info-indicators.scss for role-indicator addition --- ui/src/style/chronograf.scss | 2 +- .../components/{source-indicator.scss => info-indicators.scss} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename ui/src/style/components/{source-indicator.scss => info-indicators.scss} (100%) diff --git a/ui/src/style/chronograf.scss b/ui/src/style/chronograf.scss index 2be5b0290f..79fbcc3e9d 100644 --- a/ui/src/style/chronograf.scss +++ b/ui/src/style/chronograf.scss @@ -49,7 +49,7 @@ @import 'components/redacted-input'; @import 'components/resizer'; @import 'components/search-widget'; -@import 'components/source-indicator'; +@import 'components/info-indicators'; @import 'components/source-selector'; @import 'components/tables'; diff --git a/ui/src/style/components/source-indicator.scss b/ui/src/style/components/info-indicators.scss similarity index 100% rename from ui/src/style/components/source-indicator.scss rename to ui/src/style/components/info-indicators.scss From 32cae8935bef6ea13f579ca7a72283cca4eb7c22 Mon Sep 17 00:00:00 2001 From: Alex Paxton Date: Fri, 27 Oct 2017 17:06:06 -0700 Subject: [PATCH 41/43] Fix & clean up Authorized render logic Signed-off-by: Jared Scheib --- ui/src/auth/Authorized.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index d27fab7282..5b180a35c4 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -49,25 +49,25 @@ const Authorized = ({ return null } - const meRole = getMeRole(me) + // React.isValidElement guards against multiple children wrapped by Authorized + const elementToClone = React.isValidElement(children) ? children : children[0] - if (!isUsingAuth || isUserAuthorized(meRole, requiredRole)) { - return React.cloneElement( - React.isValidElement(children) ? children : children[0], - {...additionalProps, ...propsOverride} - ) // guards against multiple children wrapped by Authorized - } else if ( - isUsingAuth && - !isUserAuthorized(meRole, requiredRole) && - propsOverride - ) { - return React.cloneElement( - React.isValidElement(children) ? children : children[0], - {...additionalProps, ...propsOverride} - ) + if (!isUsingAuth) { + return React.cloneElement(elementToClone, {...additionalProps}) } - return replaceWith || null + const meRole = getMeRole(me) + + if (!isUserAuthorized(meRole, requiredRole)) { + return propsOverride + ? React.cloneElement(elementToClone, { + ...additionalProps, + ...propsOverride, + }) + : replaceWith || null + } + + return React.cloneElement(elementToClone, {...additionalProps}) // if you want elements to be disabled instead of hidden: // return React.cloneElement(clonedElement, {disabled: !isAuthorized}) From d184b05cc2f10c370fec65254c7c30f9c184e4d8 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 27 Oct 2017 17:24:50 -0700 Subject: [PATCH 42/43] Refactor Authorized return logic to be in the affirmative Signed-off-by: Luke Morris --- ui/src/auth/Authorized.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index 5b180a35c4..0cb47d35d4 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -52,22 +52,20 @@ const Authorized = ({ // React.isValidElement guards against multiple children wrapped by Authorized const elementToClone = React.isValidElement(children) ? children : children[0] - if (!isUsingAuth) { + const meRole = getMeRole(me) + + if (!isUsingAuth || isUserAuthorized(meRole, requiredRole)) { return React.cloneElement(elementToClone, {...additionalProps}) } - const meRole = getMeRole(me) - - if (!isUserAuthorized(meRole, requiredRole)) { - return propsOverride - ? React.cloneElement(elementToClone, { - ...additionalProps, - ...propsOverride, - }) - : replaceWith || null + if (propsOverride) { + return React.cloneElement(elementToClone, { + ...additionalProps, + ...propsOverride, + }) } - return React.cloneElement(elementToClone, {...additionalProps}) + return replaceWith || null // if you want elements to be disabled instead of hidden: // return React.cloneElement(clonedElement, {disabled: !isAuthorized}) From 6e405e16514adf4df9482c2270bec7831f4ea3f2 Mon Sep 17 00:00:00 2001 From: Luke Morris Date: Fri, 27 Oct 2017 17:34:55 -0700 Subject: [PATCH 43/43] Refactor SideNav & NavBlock to remove unnecessary cloneElement Remove additionalProps & some cloneElement need from Authorized. Incidentally fix dispatch error from throwing. Clean up. Signed-off-by: Jared Scheib --- ui/src/auth/Authorized.js | 13 +++------- ui/src/side_nav/components/NavItems.js | 12 +--------- ui/src/side_nav/containers/SideNav.js | 33 +++++++++++++++++++++----- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index 0cb47d35d4..e8eefc1bd9 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -42,7 +42,6 @@ const Authorized = ({ requiredRole, replaceWith, propsOverride, - ...additionalProps }) => { // if me response has not been received yet, render nothing if (typeof isUsingAuth !== 'boolean') { @@ -50,25 +49,19 @@ const Authorized = ({ } // React.isValidElement guards against multiple children wrapped by Authorized - const elementToClone = React.isValidElement(children) ? children : children[0] + const firstChild = React.isValidElement(children) ? children : children[0] const meRole = getMeRole(me) if (!isUsingAuth || isUserAuthorized(meRole, requiredRole)) { - return React.cloneElement(elementToClone, {...additionalProps}) + return firstChild } if (propsOverride) { - return React.cloneElement(elementToClone, { - ...additionalProps, - ...propsOverride, - }) + return React.cloneElement(firstChild, {...propsOverride}) } return replaceWith || null - - // if you want elements to be disabled instead of hidden: - // return React.cloneElement(clonedElement, {disabled: !isAuthorized}) } const {arrayOf, bool, node, shape, string} = PropTypes diff --git a/ui/src/side_nav/components/NavItems.js b/ui/src/side_nav/components/NavItems.js index 91aa8e1303..c0761582a7 100644 --- a/ui/src/side_nav/components/NavItems.js +++ b/ui/src/side_nav/components/NavItems.js @@ -2,8 +2,6 @@ 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({ @@ -115,19 +113,11 @@ const NavBlock = React.createClass({ const NavBar = React.createClass({ propTypes: { children: node, - location: string.isRequired, }, render() { - const children = React.Children.map(this.props.children, child => { - if (child && (child.type === NavBlock || child.type === Authorized)) { - return React.cloneElement(child, { - location: this.props.location, - }) - } + const {children} = this.props - return child - }) return (
- + {s.name} + + } > - - {s.name} - - {s.default ? ' (Default)' : null} - + + + {s.name} + + {s.default ? ' (Default)' : null} + +
{s.url}
- - Delete Source - + + + Delete Source + + {kapacitorDropdown( From c8163b68aa02e31267af7ebaaccff160221aa04b Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 14:14:35 -0700 Subject: [PATCH 21/43] Create component to indicate current role to the user --- ui/src/shared/components/RoleIndicator.js | 55 +++++++++++++++++++ ui/src/style/components/react-tooltips.scss | 4 ++ ui/src/style/components/source-indicator.scss | 5 +- 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 ui/src/shared/components/RoleIndicator.js diff --git a/ui/src/shared/components/RoleIndicator.js b/ui/src/shared/components/RoleIndicator.js new file mode 100644 index 0000000000..c425c18c81 --- /dev/null +++ b/ui/src/shared/components/RoleIndicator.js @@ -0,0 +1,55 @@ +import React, {PropTypes} from 'react' +import uuid from 'node-uuid' + +import {connect} from 'react-redux' + +import ReactTooltip from 'react-tooltip' + +const getRoleName = ({roles: [{name}, ..._]}) => name + +const RoleIndicator = ({me, isUsingAuth}) => { + if (!isUsingAuth) { + return null + } + + const roleName = getRoleName(me) + const RoleTooltip = `

Role: ${roleName}

` + const uuidTooltip = uuid.v4() + + return ( +
+ + +
+ ) +} + +const {arrayOf, bool, shape, string} = PropTypes + +RoleIndicator.propTypes = { + isUsingAuth: bool.isRequired, + me: shape({ + roles: arrayOf( + shape({ + name: string.isRequired, + }) + ), + }), +} + +const mapStateToProps = ({auth: {me, isUsingAuth}}) => ({ + me, + isUsingAuth, +}) + +export default connect(mapStateToProps)(RoleIndicator) diff --git a/ui/src/style/components/react-tooltips.scss b/ui/src/style/components/react-tooltips.scss index 7dcccf4146..2c1e8540da 100644 --- a/ui/src/style/components/react-tooltips.scss +++ b/ui/src/style/components/react-tooltips.scss @@ -46,6 +46,10 @@ $tooltip-code-color: $c-potassium; line-height: 1.125em; letter-spacing: 0; font-family: $default-font; + + &:only-child { + margin: 0; + } } p { diff --git a/ui/src/style/components/source-indicator.scss b/ui/src/style/components/source-indicator.scss index 60099d3b3a..82f2fe51dd 100644 --- a/ui/src/style/components/source-indicator.scss +++ b/ui/src/style/components/source-indicator.scss @@ -1,7 +1,8 @@ /* - Source Indicator component styles - ---------------------------------------------------------------- + Source & Role Indicator component styles + ---------------------------------------------------------------------------- */ +.role-indicator, .source-indicator { @include no-user-select(); display: inline-block; From 95917837e37b3536f46128e90f4b31dd550863cf Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 25 Oct 2017 16:22:00 -0700 Subject: [PATCH 22/43] 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 --- ui/src/auth/Authorized.js | 25 +++++++++++++++++-------- ui/src/side_nav/components/NavItems.js | 11 ++++++----- ui/src/side_nav/containers/SideNav.js | 10 +++++++--- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index 6a2d2ac283..f0dddd7c41 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -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({ diff --git a/ui/src/side_nav/components/NavItems.js b/ui/src/side_nav/components/NavItems.js index 4977b4b35f..e5871f12dc 100644 --- a/ui/src/side_nav/components/NavItems.js +++ b/ui/src/side_nav/components/NavItems.js @@ -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, }) diff --git a/ui/src/side_nav/containers/SideNav.js b/ui/src/side_nav/containers/SideNav.js index 113b4727f3..8280a00527 100644 --- a/ui/src/side_nav/containers/SideNav.js +++ b/ui/src/side_nav/containers/SideNav.js @@ -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 - - - + + + + + Date: Wed, 25 Oct 2017 16:57:42 -0700 Subject: [PATCH 23/43] WIP Introduce propsOverride to Authorized HOC to limit props based on authorization Signed-off-by: Jared Scheib --- ui/src/auth/Authorized.js | 5 +- ui/src/shared/components/Dropdown.js | 2 +- ui/src/sources/components/InfluxTable.js | 59 +++++++++++++----------- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index f0dddd7c41..368aacdbc6 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -1,5 +1,4 @@ import React, {PropTypes} from 'react' - import {connect} from 'react-redux' export const VIEWER_ROLE = 'viewer' @@ -39,6 +38,7 @@ const Authorized = ({ isUsingAuth, requiredRole, replaceWith, + propsOverride, ...additionalProps }) => { // if me response has not been received yet, render nothing @@ -50,7 +50,7 @@ const Authorized = ({ if (!isUsingAuth || isUserAuthorized(meRole, requiredRole)) { return React.cloneElement( React.isValidElement(children) ? children : children[0], - {...additionalProps} + {...additionalProps, ...propsOverride} ) // guards against multiple children wrapped by Authorized } @@ -74,6 +74,7 @@ Authorized.propTypes = { ), }), requiredRole: string.isRequired, + propsOverride: shape(), } const mapStateToProps = ({auth: {me, isUsingAuth}}) => ({ diff --git a/ui/src/shared/components/Dropdown.js b/ui/src/shared/components/Dropdown.js index 92efa21028..b0d4093818 100644 --- a/ui/src/shared/components/Dropdown.js +++ b/ui/src/shared/components/Dropdown.js @@ -164,7 +164,7 @@ class Dropdown extends Component { > {item.text} - {actions.length > 0 + {actions ?
{actions.map(action => { return ( diff --git a/ui/src/sources/components/InfluxTable.js b/ui/src/sources/components/InfluxTable.js index 675ea8e861..dead3eab16 100644 --- a/ui/src/sources/components/InfluxTable.js +++ b/ui/src/sources/components/InfluxTable.js @@ -41,35 +41,40 @@ const kapacitorDropdown = ( } return ( - { - router.push(`${item.resource}/edit`) + + { + router.push(`${item.resource}/edit`) + }, }, - }, - { - icon: 'trash', - text: 'delete', - handler: item => { - handleDeleteKapacitor(item.kapacitor) + { + icon: 'trash', + text: 'delete', + handler: item => { + handleDeleteKapacitor(item.kapacitor) + }, + confirmable: true, }, - confirmable: true, - }, - ]} - selected={selected} - /> + ]} + selected={selected} + /> + ) } From 01b88e23f53c97d5f0ca601a7abcc302d992ce31 Mon Sep 17 00:00:00 2001 From: Alex Paxton Date: Wed, 25 Oct 2017 17:00:27 -0700 Subject: [PATCH 24/43] Remove location required from NavItems propTypes since not always available immediately Signed-off-by: Jared Scheib --- ui/src/side_nav/components/NavItems.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/side_nav/components/NavItems.js b/ui/src/side_nav/components/NavItems.js index e5871f12dc..91aa8e1303 100644 --- a/ui/src/side_nav/components/NavItems.js +++ b/ui/src/side_nav/components/NavItems.js @@ -10,7 +10,7 @@ const NavListItem = React.createClass({ propTypes: { link: string.isRequired, children: node, - location: string.isRequired, + location: string, useAnchor: bool, isExternal: bool, }, @@ -62,7 +62,7 @@ const NavBlock = React.createClass({ children: node, link: string, icon: string.isRequired, - location: string.isRequired, + location: string, className: string, }, From 6fcef2ee37105d7766dad529731bd7ca6d1426e4 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 18:30:35 -0700 Subject: [PATCH 25/43] Guard against empty arrays of dropdown actions --- ui/src/shared/components/Dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/components/Dropdown.js b/ui/src/shared/components/Dropdown.js index b0d4093818..33d93aafb7 100644 --- a/ui/src/shared/components/Dropdown.js +++ b/ui/src/shared/components/Dropdown.js @@ -164,7 +164,7 @@ class Dropdown extends Component { > {item.text} - {actions + {actions && actions.length ?
{actions.map(action => { return ( From 61f2e37da793577954aa77ffefcf770281b29a20 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 18:31:25 -0700 Subject: [PATCH 26/43] Allow render of Authorized child if propsOverride has been specified MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this case we don’t want to obscure the wrapped component, just render it with some props modified --- ui/src/auth/Authorized.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ui/src/auth/Authorized.js b/ui/src/auth/Authorized.js index 368aacdbc6..ec43cbdb5c 100644 --- a/ui/src/auth/Authorized.js +++ b/ui/src/auth/Authorized.js @@ -52,6 +52,15 @@ const Authorized = ({ React.isValidElement(children) ? children : children[0], {...additionalProps, ...propsOverride} ) // guards against multiple children wrapped by Authorized + } else if ( + isUsingAuth && + !isUserAuthorized(meRole, requiredRole) && + propsOverride + ) { + return React.cloneElement( + React.isValidElement(children) ? children : children[0], + {...additionalProps, ...propsOverride} + ) } return replaceWith ? replaceWith : null From 70631f3a112b86273fe6994910ed66607bffb67d Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 18:37:45 -0700 Subject: [PATCH 27/43] Override layout resize and drag functionality based on user authorization --- ui/src/shared/components/LayoutRenderer.js | 90 +++++++++++++--------- 1 file changed, 54 insertions(+), 36 deletions(-) diff --git a/ui/src/shared/components/LayoutRenderer.js b/ui/src/shared/components/LayoutRenderer.js index 42bcc22307..1faf1cca6e 100644 --- a/ui/src/shared/components/LayoutRenderer.js +++ b/ui/src/shared/components/LayoutRenderer.js @@ -4,6 +4,8 @@ import Resizeable from 'react-component-resizable' import _ from 'lodash' +import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized' + import Layout from 'src/shared/components/Layout' import { @@ -87,43 +89,59 @@ class LayoutRenderer extends Component { return ( - - {cells.map(cell => -
- -
- )} -
+ + {cells.map(cell => +
+ + + +
+ )} +
+
) } From 5b076aea88a18858e975771577bf0a8d01c35904 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 18:40:48 -0700 Subject: [PATCH 28/43] Render Add Config button in sources table based on user authorization --- ui/src/sources/components/InfluxTable.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ui/src/sources/components/InfluxTable.js b/ui/src/sources/components/InfluxTable.js index dead3eab16..91898debd2 100644 --- a/ui/src/sources/components/InfluxTable.js +++ b/ui/src/sources/components/InfluxTable.js @@ -15,12 +15,14 @@ const kapacitorDropdown = ( ) => { if (!kapacitors || kapacitors.length === 0) { return ( - - Add Config - + + + Add Config + + ) } const kapacitorItems = kapacitors.map(k => { From bb3777cc2ad4961e2fa35f18e8b145ced2e2e729 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 25 Oct 2017 20:13:54 -0700 Subject: [PATCH 29/43] Render Add Graph button in empty cell based on user authorization --- ui/src/shared/components/LayoutCell.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ui/src/shared/components/LayoutCell.js b/ui/src/shared/components/LayoutCell.js index ed240a026b..556638e1c9 100644 --- a/ui/src/shared/components/LayoutCell.js +++ b/ui/src/shared/components/LayoutCell.js @@ -76,12 +76,14 @@ class LayoutCell extends Component { {queries.length ? children :
- + + +
}
From 15abd3e8005f4fc71a89652bf6d4d698aac28e3d Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Thu, 26 Oct 2017 13:31:44 -0700 Subject: [PATCH 30/43] Disable rule Enabled toggle in TaskTable based on user authorization --- .../kapacitor/components/KapacitorRulesTable.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.js index e3b352fe25..d63923cdb0 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.js +++ b/ui/src/kapacitor/components/KapacitorRulesTable.js @@ -68,13 +68,15 @@ const RuleRow = ({rule, source, onDelete, onChangeRuleStatus}) =>
- + + +
- - - +
- - - Edit TICKscript - - - - - + + Edit TICKscript + +
- - - Edit TICKscript - - - - - + + Edit TICKscript + +