Load available permissions and find matching role

This commit is contained in:
René Pfeuffer
2019-01-24 09:53:26 +01:00
parent 5d3cbff461
commit 5b8518fbd9
4 changed files with 286 additions and 219 deletions

View File

@@ -1,42 +1,51 @@
// @flow // @flow
import React from "react"; import React from "react";
import { translate } from "react-i18next"; import { translate } from "react-i18next";
import { Select } from "@scm-manager/ui-components"; import { Select } from "@scm-manager/ui-components";
type Props = { type Props = {
t: string => string, t: string => string,
handleTypeChange: string => void, availableTypes: string[],
type: string, handleTypeChange: string => void,
label?: string, type: string,
helpText?: string, label?: string,
loading?: boolean helpText?: string,
}; loading?: boolean
};
class TypeSelector extends React.Component<Props> {
render() { class TypeSelector extends React.Component<Props> {
const { type, handleTypeChange, loading, label, helpText } = this.props; render() {
const types = ["READ", "OWNER", "WRITE"]; const {
availableTypes,
return ( type,
<Select handleTypeChange,
onChange={handleTypeChange} loading,
value={type ? type : "READ"} label,
options={this.createSelectOptions(types)} helpText
loading={loading} } = this.props;
label={label}
helpText={helpText} if (!availableTypes) return null;
/>
); return (
} <Select
onChange={handleTypeChange}
createSelectOptions(types: string[]) { value={type ? type : availableTypes[0]}
return types.map(type => { options={this.createSelectOptions(availableTypes)}
return { loading={loading}
label: type, label={label}
value: type helpText={helpText}
}; />
}); );
} }
}
createSelectOptions(types: string[]) {
export default translate("repos")(TypeSelector); return types.map(type => {
return {
label: type,
value: type
};
});
}
}
export default translate("repos")(TypeSelector);

View File

@@ -6,6 +6,7 @@ import {
fetchAvailablePermissionsIfNeeded, fetchAvailablePermissionsIfNeeded,
fetchPermissions, fetchPermissions,
getFetchAvailablePermissionsFailure, getFetchAvailablePermissionsFailure,
getAvailablePermissions,
getFetchPermissionsFailure, getFetchPermissionsFailure,
isFetchAvailablePermissionsPending, isFetchAvailablePermissionsPending,
isFetchPermissionsPending, isFetchPermissionsPending,
@@ -22,6 +23,7 @@ import {
} from "../modules/permissions"; } from "../modules/permissions";
import { Loading, ErrorPage } from "@scm-manager/ui-components"; import { Loading, ErrorPage } from "@scm-manager/ui-components";
import type { import type {
AvailableRepositoryPermissions,
Permission, Permission,
PermissionCollection, PermissionCollection,
PermissionCreateEntry PermissionCreateEntry
@@ -36,6 +38,7 @@ import {
} from "../../../modules/indexResource"; } from "../../../modules/indexResource";
type Props = { type Props = {
availablePermissions: AvailableRepositoryPermissions,
namespace: string, namespace: string,
repoName: string, repoName: string,
loading: boolean, loading: boolean,
@@ -97,6 +100,7 @@ class Permissions extends React.Component<Props> {
render() { render() {
const { const {
availablePermissions,
loading, loading,
error, error,
permissions, permissions,
@@ -118,7 +122,7 @@ class Permissions extends React.Component<Props> {
); );
} }
if (loading || !permissions) { if (loading || !permissions || !availablePermissions) {
return <Loading />; return <Loading />;
} }
@@ -149,6 +153,7 @@ class Permissions extends React.Component<Props> {
{permissions.map(permission => { {permissions.map(permission => {
return ( return (
<SinglePermission <SinglePermission
availablePermissions={availablePermissions}
key={permission.name + permission.groupPermission.toString()} key={permission.name + permission.groupPermission.toString()}
namespace={namespace} namespace={namespace}
repoName={repoName} repoName={repoName}
@@ -186,7 +191,9 @@ const mapStateToProps = (state, ownProps) => {
const permissionsLink = getPermissionsLink(state, namespace, repoName); const permissionsLink = getPermissionsLink(state, namespace, repoName);
const groupAutoCompleteLink = getGroupAutoCompleteLink(state); const groupAutoCompleteLink = getGroupAutoCompleteLink(state);
const userAutoCompleteLink = getUserAutoCompleteLink(state); const userAutoCompleteLink = getUserAutoCompleteLink(state);
const availablePermissions = getAvailablePermissions(state);
return { return {
availablePermissions,
namespace, namespace,
repoName, repoName,
error, error,

View File

@@ -1,176 +1,221 @@
// @flow // @flow
import React from "react"; import React from "react";
import type { Permission } from "@scm-manager/ui-types"; import type {
import { translate } from "react-i18next"; AvailableRepositoryPermissions,
import { Permission
modifyPermission, } from "@scm-manager/ui-types";
isModifyPermissionPending, import { translate } from "react-i18next";
deletePermission, import {
isDeletePermissionPending modifyPermission,
} from "../modules/permissions"; isModifyPermissionPending,
import { connect } from "react-redux"; deletePermission,
import type { History } from "history"; isDeletePermissionPending
import { Checkbox } from "@scm-manager/ui-components"; } from "../modules/permissions";
import DeletePermissionButton from "../components/buttons/DeletePermissionButton"; import { connect } from "react-redux";
import TypeSelector from "../components/TypeSelector"; import type { History } from "history";
import { Checkbox } from "@scm-manager/ui-components";
type Props = { import DeletePermissionButton from "../components/buttons/DeletePermissionButton";
submitForm: Permission => void, import TypeSelector from "../components/TypeSelector";
modifyPermission: (Permission, string, string) => void,
permission: Permission, type Props = {
t: string => string, availablePermissions: AvailableRepositoryPermissions,
namespace: string, submitForm: Permission => void,
repoName: string, modifyPermission: (Permission, string, string) => void,
match: any, permission: Permission,
history: History, t: string => string,
loading: boolean, namespace: string,
deletePermission: (Permission, string, string) => void, repoName: string,
deleteLoading: boolean match: any,
}; history: History,
loading: boolean,
type State = { deletePermission: (Permission, string, string) => void,
permission: Permission deleteLoading: boolean
}; };
class SinglePermission extends React.Component<Props, State> { type State = {
constructor(props: Props) { role: string,
super(props); permission: Permission
};
this.state = {
permission: { class SinglePermission extends React.Component<Props, State> {
name: "", constructor(props: Props) {
type: "READ", super(props);
groupPermission: false,
_links: {} const defaultPermission = props.availablePermissions.availableRoles
} ? props.availablePermissions.availableRoles[0]
}; : {};
}
this.state = {
componentDidMount() { permission: {
const { permission } = this.props; name: "",
if (permission) { verbs: defaultPermission.verbs,
this.setState({ groupPermission: false,
permission: { _links: {}
name: permission.name, },
type: permission.type, role: defaultPermission.name
groupPermission: permission.groupPermission, };
_links: permission._links }
}
}); componentDidMount() {
} const { permission } = this.props;
}
const matchingRole = this.findMatchingRoleName();
deletePermission = () => {
this.props.deletePermission( if (permission) {
this.props.permission, this.setState({
this.props.namespace, permission: {
this.props.repoName name: permission.name,
); verbs: permission.verbs,
}; groupPermission: permission.groupPermission,
_links: permission._links
render() { },
const { permission } = this.state; role: matchingRole
const { loading, namespace, repoName } = this.props; });
const typeSelector = }
this.props.permission._links && this.props.permission._links.update ? ( }
<td>
<TypeSelector findMatchingRoleName = () => {
handleTypeChange={this.handleTypeChange} const { availablePermissions, permission } = this.props;
type={permission.type ? permission.type : "READ"} if (!permission) {
loading={loading} return "";
/> }
</td> const matchingRole = availablePermissions.availableRoles.find(role => {
) : ( return this.equalVerbs(role.verbs, permission.verbs);
<td>{permission.type}</td> });
);
if (matchingRole) {
return ( return matchingRole.name;
<tr> } else {
<td>{permission.name}</td> return "";
<td> }
<Checkbox checked={permission ? permission.groupPermission : false} /> };
</td> equalVerbs = (verbs1: string[], verbs2: string[]) => {
{typeSelector} if (!verbs1 || !verbs2) {
<td> return false;
<DeletePermissionButton }
permission={permission}
namespace={namespace} if (verbs1.length !== verbs2.length) {
repoName={repoName} return false;
deletePermission={this.deletePermission} }
loading={this.props.deleteLoading}
/> return verbs1.every(verb => verbs2.includes(verb));
</td> };
</tr>
); deletePermission = () => {
} this.props.deletePermission(
this.props.permission,
handleTypeChange = (type: string) => { this.props.namespace,
this.setState({ this.props.repoName
permission: { );
...this.state.permission, };
type: type
} render() {
}); const { role, permission } = this.state;
this.modifyPermission(type); const { availablePermissions, loading, namespace, repoName } = this.props;
}; const availableRoleNames = availablePermissions.availableRoles.map(
r => r.name
modifyPermission = (type: string) => { );
let permission = this.state.permission; const typeSelector =
permission.type = type; this.props.permission._links && this.props.permission._links.update ? (
this.props.modifyPermission( <td>
permission, <TypeSelector
this.props.namespace, handleTypeChange={this.handleTypeChange}
this.props.repoName availableTypes={availableRoleNames}
); type={role}
}; loading={loading}
/>
createSelectOptions(types: string[]) { </td>
return types.map(type => { ) : (
return { <td>{role}</td>
label: type, );
value: type
}; return (
}); <tr>
} <td>{permission.name}</td>
} <td>
<Checkbox checked={permission ? permission.groupPermission : false} />
const mapStateToProps = (state, ownProps) => { </td>
const permission = ownProps.permission; {typeSelector}
const loading = isModifyPermissionPending( <td>
state, <DeletePermissionButton
ownProps.namespace, permission={permission}
ownProps.repoName, namespace={namespace}
permission repoName={repoName}
); deletePermission={this.deletePermission}
const deleteLoading = isDeletePermissionPending( loading={this.props.deleteLoading}
state, />
ownProps.namespace, </td>
ownProps.repoName, </tr>
permission );
); }
return { loading, deleteLoading }; handleTypeChange = (type: string) => {
}; this.setState({
permission: {
const mapDispatchToProps = dispatch => { ...this.state.permission,
return { type: type
modifyPermission: ( }
permission: Permission, });
namespace: string, this.modifyPermission(type);
repoName: string };
) => {
dispatch(modifyPermission(permission, namespace, repoName)); modifyPermission = (type: string) => {
}, let permission = this.state.permission;
deletePermission: ( permission.type = type;
permission: Permission, this.props.modifyPermission(
namespace: string, permission,
repoName: string this.props.namespace,
) => { this.props.repoName
dispatch(deletePermission(permission, namespace, repoName)); );
} };
};
}; createSelectOptions(types: string[]) {
export default connect( return types.map(type => {
mapStateToProps, return {
mapDispatchToProps label: type,
)(translate("repos")(SinglePermission)); 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));

View File

@@ -534,6 +534,12 @@ export default function reducer(
// selectors // selectors
export function getAvailablePermissions(state: Object) {
if (state.permissions) {
return state.permissions.available;
}
}
export function getPermissionsOfRepo( export function getPermissionsOfRepo(
state: Object, state: Object,
namespace: string, namespace: string,