From 601fff5b40829a077022c9e7141d109df0044165 Mon Sep 17 00:00:00 2001 From: Pavel Zavora Date: Wed, 1 Jun 2022 09:03:34 +0200 Subject: [PATCH] feat(ui): changes Roles page to show users and effective RW per DB --- ui/src/admin/components/RoleRow.tsx | 130 ++++----- ui/src/admin/constants/tableSizing.js | 9 +- .../admin/containers/influxdb/RolesPage.tsx | 250 +++++++++++++----- 3 files changed, 226 insertions(+), 163 deletions(-) diff --git a/ui/src/admin/components/RoleRow.tsx b/ui/src/admin/components/RoleRow.tsx index ffb466ac1..6b410b968 100644 --- a/ui/src/admin/components/RoleRow.tsx +++ b/ui/src/admin/components/RoleRow.tsx @@ -1,115 +1,81 @@ -import React, {useCallback, useMemo} from 'react' +import React from 'react' import RoleRowEdit from 'src/admin/components/RoleRowEdit' -import MultiSelectDropdown from 'src/shared/components/MultiSelectDropdown' -import ConfirmButton from 'src/shared/components/ConfirmButton' import {ROLES_TABLE} from 'src/admin/constants/tableSizing' -import {UserPermission, UserRole, User} from 'src/types/influxAdmin' -import classnames from 'classnames' +import {UserRole} from 'src/types/influxAdmin' +import {Link} from 'react-router' +import {PERMISSIONS} from 'src/shared/constants' interface Props { role: UserRole - allUsers: User[] - allPermissions: string[] + allUsers: any[] + page: string + perDBPermissions: Array> + showUsers: boolean onCancel: (role: UserRole) => void onEdit: (role: UserRole, updates: Partial) => void onSave: (role: UserRole) => Promise - onDelete: (role: UserRole) => Promise - onUpdateRoleUsers: (role: UserRole, users: User[]) => void - onUpdateRolePermissions: ( - role: UserRole, - permissions: UserPermission[] - ) => void } const RoleRow = ({ - role: {name: roleName, permissions, users = [], isEditing}, role, allUsers, - allPermissions, + page, + perDBPermissions, + showUsers, onEdit, onSave, onCancel, - onDelete, - onUpdateRoleUsers, - onUpdateRolePermissions, }: Props) => { - const handleUpdateUsers = useCallback( - (usrs: User[]) => onUpdateRoleUsers(role, usrs), - [role] - ) - const handleUpdatePermissions = useCallback( - (allowed: Array<{name: string}>) => - onUpdateRolePermissions(role, [ - {scope: 'all', allowed: allowed.map(({name}) => name)}, - ]), - [role] - ) - const selectedPerms = useMemo(() => { - const allPerm = permissions?.find(x => x.scope === 'all') - return allPerm?.allowed.map((name: string) => ({name})) || [] - }, [permissions]) - - if (isEditing) { + if (role.isEditing) { return ( ) } - const wrappedDelete = () => { - onDelete(role) - } - return ( - - {roleName} - - {allPermissions && allPermissions.length ? ( - ({name}))} - selectedItems={selectedPerms} - label={selectedPerms.length ? '' : 'Select Permissions'} - onApply={handleUpdatePermissions} - buttonSize="btn-xs" - buttonColor="btn-primary" - customClass={classnames(`dropdown-${ROLES_TABLE.colPermissions}`, { - 'admin-table--multi-select-empty': !permissions.length, - })} - resetStateOnReceiveProps={false} - /> - ) : null} - - - {allUsers && allUsers.length ? ( - - ) : null} - - - + + + {role.name} + {showUsers && ( + + {role.users.map((user, i) => ( + + {user.name} + + ))} + + )} + {perDBPermissions.map((perms, i) => ( + + + {PERMISSIONS.ReadData.displayName} + + + {PERMISSIONS.WriteData.displayName} + + + ))} ) } diff --git a/ui/src/admin/constants/tableSizing.js b/ui/src/admin/constants/tableSizing.js index d57a70286..8120c5f74 100644 --- a/ui/src/admin/constants/tableSizing.js +++ b/ui/src/admin/constants/tableSizing.js @@ -1,16 +1,9 @@ export const USERS_TABLE = { colUsername: 240, colAdministrator: 70, - colPassword: 186, - colRoles: 190, - colPermissions: 190, - colDelete: 110, } export const ROLES_TABLE = { - colName: 280, - colUsers: 200, - colPermissions: 200, - colDelete: 110, + colName: 240, } export const QUERIES_TABLE = { colDatabase: 160, diff --git a/ui/src/admin/containers/influxdb/RolesPage.tsx b/ui/src/admin/containers/influxdb/RolesPage.tsx index ea3f67faa..b979a5561 100644 --- a/ui/src/admin/containers/influxdb/RolesPage.tsx +++ b/ui/src/admin/containers/influxdb/RolesPage.tsx @@ -1,17 +1,14 @@ -import React, {useMemo} from 'react' +import React, {useMemo, useState} from 'react' import {connect, ResolveThunks} from 'react-redux' import {withSource} from 'src/CheckSources' import {Source} from 'src/types' -import {UserPermission, UserRole, User} from 'src/types/influxAdmin' +import {UserRole, User, Database} from 'src/types/influxAdmin' import {notify as notifyAction} from 'src/shared/actions/notifications' import { addRole as addRoleActionCreator, editRole as editRoleActionCreator, deleteRole as deleteRoleAction, createRoleAsync, - deleteRoleAsync, - updateRoleUsersAsync, - updateRolePermissionsAsync, filterRoles as filterRolesAction, } from 'src/admin/actions/influxdb' import {notifyRoleNameInvalid} from 'src/shared/copy/notifications' @@ -19,32 +16,33 @@ import AdminInfluxDBTabbedPage, { hasRoleManagement, isConnectedToLDAP, } from './AdminInfluxDBTabbedPage' -import FilterBar from 'src/admin/components/FilterBar' import FancyScrollbar from 'src/shared/components/FancyScrollbar' import EmptyRow from 'src/admin/components/EmptyRow' import RoleRow from 'src/admin/components/RoleRow' import {useCallback} from 'react' +import allOrParticularSelection from './util/allOrParticularSelection' +import computeEffectiveDBPermissions from './util/computeEffectiveDBPermissions' +import useDebounce from 'src/utils/useDebounce' +import useChangeEffect from 'src/utils/useChangeEffect' +import {ComponentSize, MultiSelectDropdown, SlideToggle} from 'src/reusable_ui' const isValidRole = (role: UserRole): boolean => { const minLen = 3 return role.name.length >= minLen } -const mapStateToProps = ({adminInfluxDB: {users, roles, permissions}}) => ({ +const mapStateToProps = ({adminInfluxDB: {databases, users, roles}}) => ({ + databases, users, roles, - permissions, }) const mapDispatchToProps = { - addRole: addRoleActionCreator, - removeRole: deleteRoleAction, - editRole: editRoleActionCreator, - createRole: createRoleAsync, - deleteRole: deleteRoleAsync, filterRoles: filterRolesAction, - updateRoleUsers: updateRoleUsersAsync, - updateRolePermissions: updateRolePermissionsAsync, + createRole: createRoleAsync, + removeRole: deleteRoleAction, + addRole: addRoleActionCreator, + editRole: editRoleActionCreator, notify: notifyAction, } @@ -52,9 +50,9 @@ interface OwnProps { source: Source } interface ConnectedProps { + databases: Database[] users: User[] roles: UserRole[] - permissions: UserPermission[] } type ReduxDispatchProps = ResolveThunks @@ -63,23 +61,16 @@ type Props = OwnProps & ConnectedProps & ReduxDispatchProps const RolesPage = ({ source, - permissions, users, roles, + databases, addRole, filterRoles, editRole, removeRole, - deleteRole, - updateRoleUsers, - updateRolePermissions, createRole, notify, }: Props) => { - const allPermissions = useMemo(() => { - const globalPermissions = permissions.find(p => p.scope === 'all') - return globalPermissions ? globalPermissions.allowed : [] - }, [permissions]) const handleSaveRole = useCallback( async (role: UserRole) => { if (!isValidRole(role)) { @@ -94,65 +85,155 @@ const RolesPage = ({ ) const isEditing = useMemo(() => roles.some(r => r.isEditing), [roles]) - if (!hasRoleManagement(source)) { - return ( - -
- Roles management is not available for the currently selected InfluxDB - Connection. -
-
- ) - } - if (isConnectedToLDAP(source)) { - return ( - -
- Users are managed via LDAP, roles management is not available. -
-
- ) - } + const rolesPage = useMemo( + () => `/sources/${source.id}/admin-influxdb/roles`, + [source] + ) + // filter databases + const [selectedDBs, setSelectedDBs] = useState(['*']) + const visibleDBNames = useMemo(() => { + if (selectedDBs.includes('*')) { + return databases.map(db => db.name) + } + return selectedDBs + }, [databases, selectedDBs]) + const changeSelectedDBs = useCallback( + (newDBs: string[]) => + setSelectedDBs((oldDBs: string[]) => { + return allOrParticularSelection(oldDBs, newDBs) + }), + [setSelectedDBs] + ) + + // effective permissions + const visibleRoles = useMemo(() => roles.filter(x => !x.hidden), [roles]) + const perDBPermissions = useMemo( + () => computeEffectiveDBPermissions(visibleRoles, visibleDBNames), + [visibleDBNames, visibleRoles] + ) + + // filter users + const [filterText, setFilterText] = useState('') + const changeFilterText = useCallback(e => setFilterText(e.target.value), [ + setFilterText, + ]) + const debouncedFilterText = useDebounce(filterText, 200) + useChangeEffect(() => { + filterRoles(debouncedFilterText) + }, [debouncedFilterText]) + + // hide users + const [showUsers, setShowUsers] = useState(true) + const changeHideUsers = useCallback(() => setShowUsers(!showUsers), [ + showUsers, + setShowUsers, + ]) + return (
- +
+
+ + +
+
+ + {databases.reduce( + (acc, db) => { + acc.push( + + {db.name} + + ) + return acc + }, + [ + + All Databases + , + , + ] + )} + +
+
+ + Show Users +
+
+ +
+
- +
- - - - + {showUsers && ( + + )} + {visibleRoles.length && visibleDBNames.length + ? visibleDBNames.map(name => ( + + )) + : null} - {roles.length ? ( - roles - .filter(r => !r.hidden) - .map(role => ( - - )) + {visibleRoles.length ? ( + visibleRoles.map((role, roleIndex) => ( + + )) ) : ( - + )}
NamePermissionsUsers + RoleUsers + {name} +
@@ -163,6 +244,29 @@ const RolesPage = ({ ) } +const RolesPageAvailable = (props: Props) => { + if (!hasRoleManagement(props.source)) { + return ( + +
+ Roles management is not available for the currently selected InfluxDB + Connection. +
+
+ ) + } + if (isConnectedToLDAP(props.source)) { + return ( + +
+ Users are managed via LDAP, roles management is not available. +
+
+ ) + } + return +} + export default withSource( - connect(mapStateToProps, mapDispatchToProps)(RolesPage) + connect(mapStateToProps, mapDispatchToProps)(RolesPageAvailable) )