From 5b8518fbd9836d60d62094c876d5b4da1c33ce5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 24 Jan 2019 09:53:26 +0100 Subject: [PATCH] Load available permissions and find matching role --- .../permissions/components/TypeSelector.js | 93 ++-- .../permissions/containers/Permissions.js | 9 +- .../containers/SinglePermission.js | 397 ++++++++++-------- .../repos/permissions/modules/permissions.js | 6 + 4 files changed, 286 insertions(+), 219 deletions(-) diff --git a/scm-ui/src/repos/permissions/components/TypeSelector.js b/scm-ui/src/repos/permissions/components/TypeSelector.js index bec2c5b278..9945fa4def 100644 --- a/scm-ui/src/repos/permissions/components/TypeSelector.js +++ b/scm-ui/src/repos/permissions/components/TypeSelector.js @@ -1,42 +1,51 @@ -// @flow -import React from "react"; -import { translate } from "react-i18next"; -import { Select } from "@scm-manager/ui-components"; - -type Props = { - t: string => string, - handleTypeChange: string => void, - type: string, - label?: string, - helpText?: string, - loading?: boolean -}; - -class TypeSelector extends React.Component { - render() { - const { type, handleTypeChange, loading, label, helpText } = this.props; - const types = ["READ", "OWNER", "WRITE"]; - - return ( - + ); + } + + createSelectOptions(types: string[]) { + return types.map(type => { + return { + label: type, + value: type + }; + }); + } +} + +export default translate("repos")(TypeSelector); diff --git a/scm-ui/src/repos/permissions/containers/Permissions.js b/scm-ui/src/repos/permissions/containers/Permissions.js index 4d17f65e16..830d71df66 100644 --- a/scm-ui/src/repos/permissions/containers/Permissions.js +++ b/scm-ui/src/repos/permissions/containers/Permissions.js @@ -6,6 +6,7 @@ import { fetchAvailablePermissionsIfNeeded, fetchPermissions, getFetchAvailablePermissionsFailure, + getAvailablePermissions, getFetchPermissionsFailure, isFetchAvailablePermissionsPending, isFetchPermissionsPending, @@ -22,6 +23,7 @@ import { } from "../modules/permissions"; import { Loading, ErrorPage } from "@scm-manager/ui-components"; import type { + AvailableRepositoryPermissions, Permission, PermissionCollection, PermissionCreateEntry @@ -36,6 +38,7 @@ import { } from "../../../modules/indexResource"; type Props = { + availablePermissions: AvailableRepositoryPermissions, namespace: string, repoName: string, loading: boolean, @@ -97,6 +100,7 @@ class Permissions extends React.Component { render() { const { + availablePermissions, loading, error, permissions, @@ -118,7 +122,7 @@ class Permissions extends React.Component { ); } - if (loading || !permissions) { + if (loading || !permissions || !availablePermissions) { return ; } @@ -149,6 +153,7 @@ class Permissions extends React.Component { {permissions.map(permission => { return ( { const permissionsLink = getPermissionsLink(state, namespace, repoName); const groupAutoCompleteLink = getGroupAutoCompleteLink(state); const userAutoCompleteLink = getUserAutoCompleteLink(state); + const availablePermissions = getAvailablePermissions(state); return { + availablePermissions, namespace, repoName, error, diff --git a/scm-ui/src/repos/permissions/containers/SinglePermission.js b/scm-ui/src/repos/permissions/containers/SinglePermission.js index 62380128be..1f260b4ae7 100644 --- a/scm-ui/src/repos/permissions/containers/SinglePermission.js +++ b/scm-ui/src/repos/permissions/containers/SinglePermission.js @@ -1,176 +1,221 @@ -// @flow -import React from "react"; -import type { Permission } from "@scm-manager/ui-types"; -import { translate } from "react-i18next"; -import { - modifyPermission, - isModifyPermissionPending, - deletePermission, - isDeletePermissionPending -} from "../modules/permissions"; -import { connect } from "react-redux"; -import type { History } from "history"; -import { Checkbox } from "@scm-manager/ui-components"; -import DeletePermissionButton from "../components/buttons/DeletePermissionButton"; -import TypeSelector from "../components/TypeSelector"; - -type Props = { - submitForm: Permission => void, - modifyPermission: (Permission, string, string) => void, - permission: Permission, - t: string => string, - namespace: string, - repoName: string, - match: any, - history: History, - loading: boolean, - deletePermission: (Permission, string, string) => void, - deleteLoading: boolean -}; - -type State = { - permission: Permission -}; - -class SinglePermission extends React.Component { - constructor(props: Props) { - super(props); - - this.state = { - permission: { - name: "", - type: "READ", - groupPermission: false, - _links: {} - } - }; - } - - componentDidMount() { - const { permission } = this.props; - if (permission) { - this.setState({ - permission: { - name: permission.name, - type: permission.type, - groupPermission: permission.groupPermission, - _links: permission._links - } - }); - } - } - - deletePermission = () => { - this.props.deletePermission( - this.props.permission, - this.props.namespace, - this.props.repoName - ); - }; - - render() { - const { permission } = this.state; - const { loading, namespace, repoName } = this.props; - const typeSelector = - this.props.permission._links && this.props.permission._links.update ? ( - - - - ) : ( - {permission.type} - ); - - return ( - - {permission.name} - - - - {typeSelector} - - - - - ); - } - - handleTypeChange = (type: string) => { - this.setState({ - permission: { - ...this.state.permission, - type: type - } - }); - this.modifyPermission(type); - }; - - modifyPermission = (type: string) => { - let permission = this.state.permission; - permission.type = type; - this.props.modifyPermission( - permission, - this.props.namespace, - this.props.repoName - ); - }; - - createSelectOptions(types: string[]) { - return types.map(type => { - return { - label: type, - value: type - }; - }); - } -} - -const mapStateToProps = (state, ownProps) => { - const permission = ownProps.permission; - const loading = isModifyPermissionPending( - state, - ownProps.namespace, - ownProps.repoName, - permission - ); - const deleteLoading = isDeletePermissionPending( - state, - ownProps.namespace, - ownProps.repoName, - permission - ); - - return { loading, deleteLoading }; -}; - -const mapDispatchToProps = dispatch => { - return { - modifyPermission: ( - permission: Permission, - namespace: string, - repoName: string - ) => { - dispatch(modifyPermission(permission, namespace, repoName)); - }, - deletePermission: ( - permission: Permission, - namespace: string, - repoName: string - ) => { - dispatch(deletePermission(permission, namespace, repoName)); - } - }; -}; -export default connect( - mapStateToProps, - mapDispatchToProps -)(translate("repos")(SinglePermission)); +// @flow +import React from "react"; +import type { + AvailableRepositoryPermissions, + Permission +} from "@scm-manager/ui-types"; +import { translate } from "react-i18next"; +import { + modifyPermission, + isModifyPermissionPending, + deletePermission, + isDeletePermissionPending +} from "../modules/permissions"; +import { connect } from "react-redux"; +import type { History } from "history"; +import { Checkbox } from "@scm-manager/ui-components"; +import DeletePermissionButton from "../components/buttons/DeletePermissionButton"; +import TypeSelector from "../components/TypeSelector"; + +type Props = { + availablePermissions: AvailableRepositoryPermissions, + submitForm: Permission => void, + modifyPermission: (Permission, string, string) => void, + permission: Permission, + t: string => string, + namespace: string, + repoName: string, + match: any, + history: History, + loading: boolean, + deletePermission: (Permission, string, string) => void, + deleteLoading: boolean +}; + +type State = { + role: string, + permission: Permission +}; + +class SinglePermission extends React.Component { + constructor(props: Props) { + super(props); + + const defaultPermission = props.availablePermissions.availableRoles + ? props.availablePermissions.availableRoles[0] + : {}; + + this.state = { + permission: { + name: "", + verbs: defaultPermission.verbs, + groupPermission: false, + _links: {} + }, + role: defaultPermission.name + }; + } + + componentDidMount() { + const { permission } = this.props; + + const matchingRole = this.findMatchingRoleName(); + + if (permission) { + this.setState({ + permission: { + name: permission.name, + verbs: permission.verbs, + groupPermission: permission.groupPermission, + _links: permission._links + }, + role: matchingRole + }); + } + } + + findMatchingRoleName = () => { + const { availablePermissions, permission } = this.props; + if (!permission) { + return ""; + } + const matchingRole = availablePermissions.availableRoles.find(role => { + return this.equalVerbs(role.verbs, permission.verbs); + }); + + if (matchingRole) { + return matchingRole.name; + } else { + return ""; + } + }; + equalVerbs = (verbs1: string[], verbs2: string[]) => { + if (!verbs1 || !verbs2) { + return false; + } + + if (verbs1.length !== verbs2.length) { + return false; + } + + return verbs1.every(verb => verbs2.includes(verb)); + }; + + deletePermission = () => { + this.props.deletePermission( + this.props.permission, + this.props.namespace, + this.props.repoName + ); + }; + + render() { + const { role, permission } = this.state; + const { availablePermissions, loading, namespace, repoName } = this.props; + const availableRoleNames = availablePermissions.availableRoles.map( + r => r.name + ); + const typeSelector = + this.props.permission._links && this.props.permission._links.update ? ( + + + + ) : ( + {role} + ); + + return ( + + {permission.name} + + + + {typeSelector} + + + + + ); + } + + handleTypeChange = (type: string) => { + this.setState({ + permission: { + ...this.state.permission, + type: type + } + }); + this.modifyPermission(type); + }; + + modifyPermission = (type: string) => { + let permission = this.state.permission; + permission.type = type; + this.props.modifyPermission( + permission, + this.props.namespace, + this.props.repoName + ); + }; + + createSelectOptions(types: string[]) { + return types.map(type => { + return { + label: type, + value: type + }; + }); + } +} + +const mapStateToProps = (state, ownProps) => { + const permission = ownProps.permission; + const loading = isModifyPermissionPending( + state, + ownProps.namespace, + ownProps.repoName, + permission + ); + const deleteLoading = isDeletePermissionPending( + state, + ownProps.namespace, + ownProps.repoName, + permission + ); + + return { loading, deleteLoading }; +}; + +const mapDispatchToProps = dispatch => { + return { + modifyPermission: ( + permission: Permission, + namespace: string, + repoName: string + ) => { + dispatch(modifyPermission(permission, namespace, repoName)); + }, + deletePermission: ( + permission: Permission, + namespace: string, + repoName: string + ) => { + dispatch(deletePermission(permission, namespace, repoName)); + } + }; +}; +export default connect( + mapStateToProps, + mapDispatchToProps +)(translate("repos")(SinglePermission)); diff --git a/scm-ui/src/repos/permissions/modules/permissions.js b/scm-ui/src/repos/permissions/modules/permissions.js index 74d0ea5bc7..02c4670815 100644 --- a/scm-ui/src/repos/permissions/modules/permissions.js +++ b/scm-ui/src/repos/permissions/modules/permissions.js @@ -534,6 +534,12 @@ export default function reducer( // selectors +export function getAvailablePermissions(state: Object) { + if (state.permissions) { + return state.permissions.available; + } +} + export function getPermissionsOfRepo( state: Object, namespace: string,