diff --git a/scm-ui/src/groups/containers/GroupForm.js b/scm-ui/src/groups/components/GroupForm.js similarity index 62% rename from scm-ui/src/groups/containers/GroupForm.js rename to scm-ui/src/groups/components/GroupForm.js index ac7566a32a..cef8f0b1a1 100644 --- a/scm-ui/src/groups/containers/GroupForm.js +++ b/scm-ui/src/groups/components/GroupForm.js @@ -5,14 +5,17 @@ import InputField from "../../components/forms/InputField"; import { SubmitButton } from "../../components/buttons"; import { translate } from "react-i18next"; import type { Group } from "../types/Group"; +import * as validator from "./groupValidation" -export interface Props { - t: string => string; - submitForm: Group => void; +type Props = { + t: string => string, + submitForm: Group => void } -export interface State { - group: Group; +type State = { + group: Group, + nameValidationError: boolean, + descriptionValidationError: boolean } class GroupForm extends React.Component { @@ -28,21 +31,27 @@ class GroupForm extends React.Component { _links: {}, members: [], type: "", - } + }, + nameValidationError: false, + descriptionValidationError: false }; } + onSubmit = (event: Event) => { event.preventDefault(); this.props.submitForm(this.state.group); }; isValid = () => { - return true; + const group = this.state.group; + return !(this.state.nameValidationError || this.state.descriptionValidationError || group.name); } submit = (event: Event) => { event.preventDefault(); - this.props.submitForm(this.state.group) + if (this.isValid) { + this.props.submitForm(this.state.group) + } } render() { @@ -51,15 +60,15 @@ class GroupForm extends React.Component {
@@ -68,19 +77,14 @@ class GroupForm extends React.Component { handleGroupNameChange = (name: string) => { this.setState({ - group: { - ...this.state.group, - name - } + nameValidationError: !validator.isNameValid(name), + group: {...this.state.group, name} }); }; handleDescriptionChange = (description: string) => { this.setState({ - group: { - ...this.state.group, - description - } + group: {...this.state.group, description } }); }; } diff --git a/scm-ui/src/groups/components/groupValidation.js b/scm-ui/src/groups/components/groupValidation.js new file mode 100644 index 0000000000..d6d7d96f51 --- /dev/null +++ b/scm-ui/src/groups/components/groupValidation.js @@ -0,0 +1,10 @@ +// @flow + +//TODO: How should a group be validated +//TODO: Tests! + +const nameRegex = /^([A-z0-9.\-_@]|[^ ]([A-z0-9.\-_@ ]*[A-z0-9.\-_@]|[^\s])?)$/; + +export const isNameValid = (name: string) => { + return nameRegex.test(name); +}; diff --git a/scm-ui/src/groups/containers/AddGroup.js b/scm-ui/src/groups/containers/AddGroup.js index 78c679eeef..6806478bdb 100644 --- a/scm-ui/src/groups/containers/AddGroup.js +++ b/scm-ui/src/groups/containers/AddGroup.js @@ -3,17 +3,19 @@ import React from "react"; import Page from "../../components/layout/Page"; import { translate } from "react-i18next"; -import GroupForm from "./GroupForm"; +import GroupForm from "../components/GroupForm"; import { connect } from "react-redux"; import { createGroup } from "../modules/groups"; import type { Group } from "../types/Group"; +import type { History } from "history"; -export interface Props { - t: string => string; - createGroup: Group => void; +type Props = { + t: string => string, + createGroup: (group: Group, callback?: () => void) => void, + history: History } -export interface State {} +type State = {} class AddGroup extends React.Component { render() { @@ -27,14 +29,18 @@ class AddGroup extends React.Component { ); } + groupCreated = () => { + console.log("pushing history") + this.props.history.push("/groups") + } createGroup = (group: Group) => { - this.props.createGroup(group); + this.props.createGroup(group, this.groupCreated) }; } const mapDispatchToProps = dispatch => { return { - createGroup: (group: Group) => dispatch(createGroup(group)) + createGroup: (group: Group, callback?: () => void) => dispatch(createGroup(group, callback)) }; }; diff --git a/scm-ui/src/groups/modules/groups.js b/scm-ui/src/groups/modules/groups.js index b91c8f2eb4..7f68fc9000 100644 --- a/scm-ui/src/groups/modules/groups.js +++ b/scm-ui/src/groups/modules/groups.js @@ -133,12 +133,16 @@ export function fetchGroupFailure(name: string, error: Error): Action { } //create group -export function createGroup(group: Group) { +export function createGroup(group: Group, callback?: () => void) { return function(dispatch: Dispatch) { dispatch(createGroupPending()); return apiClient .postWithContentType(GROUPS_URL, group, CONTENT_TYPE_GROUP) - .then(() => dispatch(createGroupSuccess())) + .then(() => { + dispatch(createGroupSuccess()) + if (callback) { + callback(); + }}) .catch(error => { dispatch( createGroupFailure( @@ -168,6 +172,11 @@ export function createGroupFailure(error: Error) { }; } +export function createGroupReset() { + return { + type: CREATE_GROUP_RESET + } +} //delete group export function deleteGroup(group: Group, callback?: () => void) { diff --git a/scm-ui/src/groups/modules/groups.test.js b/scm-ui/src/groups/modules/groups.test.js index 1b7c0fec0b..58354e25f0 100644 --- a/scm-ui/src/groups/modules/groups.test.js +++ b/scm-ui/src/groups/modules/groups.test.js @@ -205,6 +205,25 @@ describe("groups fetch()", () => { }); }); + it("should call the callback after creating group", () => { + fetchMock.postOnce(GROUPS_URL, { + status: 201 + }); + let called = false; + + const callMe = () => { + called = true; + } + const store = mockStore({}); + return store.dispatch(createGroup(humanGroup, callMe)).then(() => { + const actions = store.getActions(); + expect(actions[0].type).toEqual(CREATE_GROUP_PENDING); + expect(actions[1].type).toEqual(CREATE_GROUP_SUCCESS); + expect(called).toEqual(true); + }); + }); + + it("should fail creating group on HTTP 500", () => { fetchMock.postOnce(GROUPS_URL, { status: 500 diff --git a/scm-ui/src/users/containers/AddUser.js b/scm-ui/src/users/containers/AddUser.js index a690c147e3..0aa8fc47da 100644 --- a/scm-ui/src/users/containers/AddUser.js +++ b/scm-ui/src/users/containers/AddUser.js @@ -1,7 +1,7 @@ //@flow import React from "react"; import { connect } from "react-redux"; -import UserForm from "./../components/UserForm"; +import UserForm from "../components/UserForm"; import type { User } from "../types/User"; import type { History } from "history"; import {