diff --git a/scm-ui/public/locales/en/permissions.json b/scm-ui/public/locales/en/permissions.json index 70185f95aa..9e3dde4aec 100644 --- a/scm-ui/public/locales/en/permissions.json +++ b/scm-ui/public/locales/en/permissions.json @@ -20,5 +20,9 @@ "submit": "Yes", "cancel": "No" } + }, + "add-permission": { + "add-permission-heading": "Add new Permission", + "submit-button": "Submit" } } diff --git a/scm-ui/src/permissions/components/CreatePermissionForm.js b/scm-ui/src/permissions/components/CreatePermissionForm.js index 914a097f9c..84b51c9154 100644 --- a/scm-ui/src/permissions/components/CreatePermissionForm.js +++ b/scm-ui/src/permissions/components/CreatePermissionForm.js @@ -1,14 +1,20 @@ // @flow import React from "react"; -import type { Permission } from "../types/Permissions"; import { translate } from "react-i18next"; +import { Checkbox, InputField } from "../../components/forms"; +import TypeSelector from "./TypeSelector"; +import type { Permission } from "../types/Permissions"; +import { SubmitButton } from "../../components/buttons"; type Props = { - t: string => string + t: string => string, + createPermission: (permission: Permission) => void }; type State = { - permission: Permission + name: string, + type: string, + groupPermission: boolean }; class CreatePermissionForm extends React.Component { @@ -16,18 +22,84 @@ class CreatePermissionForm extends React.Component { super(props); this.state = { - permission: { - name: "", - type: "READ", - groupPermission: false, - _links: {} - } + name: "", + type: "READ", + groupPermission: false }; } render() { - return "Show Permissions here!"; + const { t } = this.props; + const { name, type, groupPermission } = this.state; + + return ( +
+

+ {t("add-permission.add-permission-heading")} +

+ + + + + + + + + + + + + + + +
{t("permission.name")} + +
{t("permission.group-permission")} + +
{t("permission.type")} + +
+ +
+ ); } + + submit = () => { + this.props.createPermission({ + name: this.state.name, + type: this.state.type, + groupPermission: this.state.groupPermission + }); + }; + + handleTypeChange = (type: string) => { + this.setState({ + type: type + }); + }; + + handleNameChange = (name: string) => { + this.setState({ + name: name + }); + }; + handleGroupPermissionChange = (groupPermission: boolean) => { + this.setState({ + groupPermission: groupPermission + }); + }; } export default translate("permissions")(CreatePermissionForm); diff --git a/scm-ui/src/permissions/components/TypeSelector.js b/scm-ui/src/permissions/components/TypeSelector.js new file mode 100644 index 0000000000..7c2ce45687 --- /dev/null +++ b/scm-ui/src/permissions/components/TypeSelector.js @@ -0,0 +1,39 @@ +// @flow +import React from "react"; +import { translate } from "react-i18next"; +import { Select } from "../../components/forms"; + +type Props = { + t: string => string, + handleTypeChange: string => void, + type: string, + loading?: boolean +}; + +class TypeSelector extends React.Component { + + render() { + const { t, type, handleTypeChange, loading } = this.props; + const types = ["READ", "OWNER", "GROUP"]; + + return ( + @@ -119,6 +115,7 @@ class SinglePermission extends React.Component { namespace={namespace} name={name} deletePermission={this.deletePermission} + loading={this.props.deleteLoading} /> {errorNotification} @@ -158,20 +155,34 @@ class SinglePermission extends React.Component { const mapStateToProps = (state, ownProps) => { const permission = ownProps.permission; + console.log(permission); const loading = isModifyPermissionPending( state, ownProps.namespace, ownProps.name, permission.name ); - const error = getModifyPermissionFailure( + const error = + getModifyPermissionFailure( + state, + ownProps.namespace, + ownProps.name, + permission.name + ) || + getDeletePermissionFailure( + state, + ownProps.namespace, + ownProps.name, + permission.name + ); + const deleteLoading = isDeletePermissionPending( state, ownProps.namespace, ownProps.name, permission.name ); - return { loading, error }; + return { loading, error, deleteLoading }; }; const mapDispatchToProps = dispatch => { @@ -193,10 +204,9 @@ const mapDispatchToProps = dispatch => { deletePermission: ( permission: Permission, namespace: string, - name: string, - callback: () => void + name: string ) => { - dispatch(deletePermission(permission, namespace, name, callback)); + dispatch(deletePermission(permission, namespace, name)); } }; }; diff --git a/scm-ui/src/permissions/modules/permissions.js b/scm-ui/src/permissions/modules/permissions.js index 8eaac31250..6539115887 100644 --- a/scm-ui/src/permissions/modules/permissions.js +++ b/scm-ui/src/permissions/modules/permissions.js @@ -220,7 +220,7 @@ export function createPermission( CONTENT_TYPE ) .then(() => { - dispatch(createPermissionSuccess(namespace, name)); + dispatch(createPermissionSuccess(permission, namespace, name)); if (callback) { callback(); } @@ -252,11 +252,16 @@ export function createPermissionPending( } export function createPermissionSuccess( + permission: Permission, namespace: string, name: string ): Action { return { type: CREATE_PERMISSION_SUCCESS, + payload: { + permission, + position: namespace + "/" + name + }, itemId: namespace + "/" + name }; } @@ -386,6 +391,17 @@ export default function reducer( entries: newPermission } }; + case CREATE_PERMISSION_SUCCESS: + const position = action.payload.position; + const permissions = state[action.payload.position].entries; + permissions.push(action.payload.permission); + return { + ...state, + [position]: { + ...state[position], + entries: permissions + } + }; case DELETE_PERMISSION_SUCCESS: const permissionPosition = action.payload.position; const new_Permissions = deletePermissionFromState( @@ -468,3 +484,29 @@ export function hasCreatePermission( return state.permissions[namespace + "/" + name].createPermission; else return null; } + +export function isDeletePermissionPending( + state: Object, + namespace: string, + name: string, + permissionname: string +) { + return isPending( + state, + DELETE_PERMISSION, + namespace + "/" + name + "/" + permissionname + ); +} + +export function getDeletePermissionFailure( + state: Object, + namespace: string, + name: string, + permissionname: string +) { + return getFailure( + state, + DELETE_PERMISSION, + namespace + "/" + name + "/" + permissionname + ); +} diff --git a/scm-ui/src/permissions/modules/permissions.test.js b/scm-ui/src/permissions/modules/permissions.test.js index 245fa39541..22dbae311c 100644 --- a/scm-ui/src/permissions/modules/permissions.test.js +++ b/scm-ui/src/permissions/modules/permissions.test.js @@ -16,6 +16,8 @@ import reducer, { hasCreatePermission, deletePermission, deletePermissionSuccess, + getDeletePermissionFailure, + isDeletePermissionPending, MODIFY_PERMISSION_FAILURE, MODIFY_PERMISSION_PENDING, FETCH_PERMISSIONS, @@ -27,9 +29,11 @@ import reducer, { CREATE_PERMISSION_PENDING, CREATE_PERMISSION_SUCCESS, CREATE_PERMISSION_FAILURE, + DELETE_PERMISSION, DELETE_PERMISSION_PENDING, DELETE_PERMISSION_SUCCESS, - DELETE_PERMISSION_FAILURE + DELETE_PERMISSION_FAILURE, + createPermissionSuccess } from "./permissions"; import type { Permission, PermissionCollection } from "../types/Permissions"; @@ -460,6 +464,33 @@ describe("permissions reducer", () => { expectedState["hitchhiker/puzzle42"] ); }); + + it("should add permission", () => { + const oldState = { + "hitchhiker/puzzle42": { + entries: [hitchhiker_puzzle42Permission_user_eins] + } + }; + let expectedState = { + "hitchhiker/puzzle42": { + entries: [ + hitchhiker_puzzle42Permission_user_eins, + hitchhiker_puzzle42Permission_user_zwei + ] + } + }; + const newState = reducer( + oldState, + createPermissionSuccess( + hitchhiker_puzzle42Permission_user_zwei, + "hitchhiker", + "puzzle42" + ) + ); + expect(newState["hitchhiker/puzzle42"]).toEqual( + expectedState["hitchhiker/puzzle42"] + ); + }); }); describe("permissions selectors", () => { @@ -571,4 +602,38 @@ describe("permissions selectors", () => { }; expect(hasCreatePermission(state, "hitchhiker", "puzzle42")).toEqual(false); }); + + it("should return true, when delete permission is pending", () => { + const state = { + pending: { + [DELETE_PERMISSION + "/hitchhiker/puzzle42/user_eins"]: true + } + }; + expect( + isDeletePermissionPending(state, "hitchhiker", "puzzle42", "user_eins") + ).toEqual(true); + }); + + it("should return false, when delete permissions is not pending", () => { + expect( + isDeletePermissionPending({}, "hitchiker", "puzzle42", "user_eins") + ).toEqual(false); + }); + + it("should return error when delete permissions did fail", () => { + const state = { + failure: { + [DELETE_PERMISSION + "/hitchhiker/puzzle42/user_eins"]: error + } + }; + expect( + getDeletePermissionFailure(state, "hitchhiker", "puzzle42", "user_eins") + ).toEqual(error); + }); + + it("should return undefined when delete permissions did not fail", () => { + expect( + getDeletePermissionFailure({}, "hitchhiker", "puzzle42", "user_eins") + ).toBe(undefined); + }); }); diff --git a/scm-ui/src/permissions/types/Permissions.js b/scm-ui/src/permissions/types/Permissions.js index c292347755..e3bd697fc5 100644 --- a/scm-ui/src/permissions/types/Permissions.js +++ b/scm-ui/src/permissions/types/Permissions.js @@ -5,7 +5,7 @@ export type Permission = { name: string, type: string, groupPermission: boolean, - _links: Links + _links?: Links }; export type PermissionCollection = Permission[];